diff --git a/CMakeLists.txt b/CMakeLists.txt index 26ba9aaaef0..698ceda7936 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -353,6 +353,8 @@ rocm_enable_cppcheck( # Disable because of too many FPs arithOperationsOnVoidPointer definePrefix:*test/include/test.hpp + definePrefix:*test/gpu/kernels/rocm* + definePrefix:*src/targets/gpu/kernels/include/rocm* definePrefix:*src/targets/gpu/kernels/include/migraphx/kernels/test.hpp # test/pp.cpp exercises the MIGRAPHX_PP_* metaprogramming macros directly, which # cppcheck's preprocessor cannot expand. diff --git a/src/compile_src.cpp b/src/compile_src.cpp index e3ebd924b0d..3d2de28d822 100644 --- a/src/compile_src.cpp +++ b/src/compile_src.cpp @@ -1,7 +1,7 @@ /* * The MIT License (MIT) * - * Copyright (c) 2015-2024 Advanced Micro Devices, Inc. All rights reserved. + * Copyright (c) 2015-2026 Advanced Micro Devices, Inc. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -51,7 +51,7 @@ std::vector src_compiler::compile(const std::vector& srcs) const write_buffer(full_path, src.content.data(), src.content.size()); if(src.path.extension().string() == ".cpp") { - params.emplace_back(src.path.filename().string()); + params.emplace_back(src.path.string()); if(out.empty()) out = src.path.stem().string() + out_ext; } diff --git a/src/targets/gpu/CMakeLists.txt b/src/targets/gpu/CMakeLists.txt index ee20237831e..dcda89e5768 100644 --- a/src/targets/gpu/CMakeLists.txt +++ b/src/targets/gpu/CMakeLists.txt @@ -78,8 +78,9 @@ else() set(MIGRAPHX_USE_HIPRTC ON CACHE BOOL "Use hipRTC APIs") endif() -file(GLOB KERNEL_FILES CONFIGURE_DEPENDS - ${CMAKE_CURRENT_SOURCE_DIR}/kernels/include/migraphx/kernels/*.hpp) +file(GLOB_RECURSE KERNEL_FILES CONFIGURE_DEPENDS LIST_DIRECTORIES false + ${CMAKE_CURRENT_SOURCE_DIR}/kernels/include/*.hpp +) if(NOT MIGRAPHX_USE_COMPOSABLEKERNEL) list(REMOVE_ITEM KERNEL_FILES @@ -117,6 +118,31 @@ if(HAS_HIP_LAMBDA_HOST_DEVICE) target_compile_options(compile_for_gpu INTERFACE -fhip-lambda-host-device) endif() +function(check_hip_deduction_guide VAR) + set(CMAKE_REQUIRED_LIBRARIES hip::device) + check_cxx_source_compiles(" +template +struct S +{ + T x; +}; + +template +S(T) -> S; + +__attribute__((device)) auto f() +{ + return S{1}; +} + " ${VAR}) +endfunction() +check_hip_deduction_guide(HIP_HAS_WORKING_DEDUCTION_GUIDE) + +if(NOT HIP_HAS_WORKING_DEDUCTION_GUIDE) + message(STATUS "Enable deduction guide workaround") + target_compile_definitions(compile_for_gpu INTERFACE MIGRAPHX_WORKAROUND_BROKEN_DEDUCTION_GUIDE=1) +endif() + set_target_properties(migraphx_device PROPERTIES EXPORT_NAME device) rocm_set_soversion(migraphx_device ${MIGRAPHX_SO_VERSION}) rocm_add_version_resource(migraphx_device "AMD MIGraphX" "MIGraphX Device Library - GPU Device Operations") @@ -176,18 +202,22 @@ endif() add_library(migraphx_gpu_kernel_file_check EXCLUDE_FROM_ALL) -set(CK_TIDY_SKIP_KERNEL_FILES "ck" "ck_gemm" "ck_gemm_softmax_gemm") +set(CK_TIDY_SKIP_KERNEL_FILES ck ck_gemm ck_gemm_softmax_gemm) foreach(KERNEL_FILE ${KERNEL_FILES}) - get_filename_component(KERNEL_BASE_FILE ${KERNEL_FILE} NAME_WE) + file(RELATIVE_PATH KERNEL_FILE_REL ${CMAKE_CURRENT_SOURCE_DIR}/kernels/include/ ${KERNEL_FILE}) + get_filename_component(KERNEL_BASE_FILE ${KERNEL_FILE_REL} NAME_WE) + get_filename_component(KERNEL_DIR ${KERNEL_FILE_REL} DIRECTORY) # Temporary workaround for tidy issue that arises from the fact that CK no longer exposes headers to the host code if(${KERNEL_BASE_FILE} IN_LIST CK_TIDY_SKIP_KERNEL_FILES) continue() endif() - file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/kernels/include/migraphx/kernels/${KERNEL_BASE_FILE}.cpp "#include \n") - target_sources(migraphx_gpu_kernel_file_check PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/kernels/include/migraphx/kernels/${KERNEL_BASE_FILE}.cpp) + file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/kernels/include/${KERNEL_DIR}/${KERNEL_BASE_FILE}.cpp "#include <${KERNEL_DIR}/${KERNEL_BASE_FILE}.hpp>\n") + target_sources(migraphx_gpu_kernel_file_check PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/kernels/include/${KERNEL_DIR}/${KERNEL_BASE_FILE}.cpp) endforeach() target_link_libraries(migraphx_gpu_kernel_file_check compile_migraphx_gpu_kernels) +# Copy the .clang-tidy files over +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/kernels/include/rocm/.clang-tidy ${CMAKE_CURRENT_BINARY_DIR}/kernels/include/rocm/.clang-tidy COPYONLY) rocm_clang_tidy_check(migraphx_gpu_kernel_file_check) diff --git a/src/targets/gpu/compile_hip_code_object.cpp b/src/targets/gpu/compile_hip_code_object.cpp index 868153c2c9e..75a478ff29b 100644 --- a/src/targets/gpu/compile_hip_code_object.cpp +++ b/src/targets/gpu/compile_hip_code_object.cpp @@ -213,7 +213,7 @@ compile_hip_raw(context& ctx, const std::string& content, hip_compile_options op kernels.end(), std::back_inserter(srcs), [](const std::pair& elem) { return src_file{elem}; }); - srcs.emplace_back("main.cpp", content); + srcs.emplace_back(options.src_file, content); if(options.global % options.local != 0 and hip_accept_non_uniform_wg()) options.emplace_param("-fno-offload-uniform-block"); diff --git a/src/targets/gpu/include/migraphx/gpu/compile_hip_code_object.hpp b/src/targets/gpu/include/migraphx/gpu/compile_hip_code_object.hpp index 130821db7b7..222ab4837c9 100644 --- a/src/targets/gpu/include/migraphx/gpu/compile_hip_code_object.hpp +++ b/src/targets/gpu/include/migraphx/gpu/compile_hip_code_object.hpp @@ -48,6 +48,7 @@ struct hip_compile_options std::vector virtual_inputs = {}; std::vector additional_src_files = {}; std::int64_t output_arg = -1; + std::string src_file = "main.cpp"; /** * @brief Set the launch parameters but allow v to override the values diff --git a/src/targets/gpu/kernels/include/migraphx/kernels/test.hpp b/src/targets/gpu/kernels/include/migraphx/kernels/test.hpp index 9c47d204883..095005f0171 100644 --- a/src/targets/gpu/kernels/include/migraphx/kernels/test.hpp +++ b/src/targets/gpu/kernels/include/migraphx/kernels/test.hpp @@ -338,6 +338,14 @@ struct test_manager __device__ [[maybe_unused]] static void __VA_ARGS__( \ [[maybe_unused]] migraphx::test::test_manager& migraphx_private_test_manager) +// NOLINTNEXTLINE +#define TEST_CASE_TEMPLATE(...) \ + __device__ [[maybe_unused]] static void __VA_ARGS__( \ + [[maybe_unused]] migraphx::test::test_manager& migraphx_private_test_manager) + +// NOLINTNEXTLINE +#define TEST_CASE_REGISTER(...) + } // namespace test } // namespace migraphx #endif // MIGRAPHX_GUARD_KERNELS_TEST_HPP diff --git a/src/targets/gpu/kernels/include/rocm/.clang-tidy b/src/targets/gpu/kernels/include/rocm/.clang-tidy new file mode 100644 index 00000000000..843a27cb54f --- /dev/null +++ b/src/targets/gpu/kernels/include/rocm/.clang-tidy @@ -0,0 +1,6 @@ +InheritParentConfig: True +CheckOptions: + - key: readability-identifier-naming.MacroDefinitionPrefix + value: ROCM_ + - key: readability-identifier-naming.ConstexprMethodIgnoredRegexp + value: 'quiet_NaN|signaling_NaN' diff --git a/src/targets/gpu/kernels/include/rocm/algorithm.hpp b/src/targets/gpu/kernels/include/rocm/algorithm.hpp new file mode 100644 index 00000000000..77568cedbde --- /dev/null +++ b/src/targets/gpu/kernels/include/rocm/algorithm.hpp @@ -0,0 +1,55 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2025-2026 Advanced Micro Devices, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#ifndef ROCM_GUARD_ROCM_ALGORITHM_HPP +#define ROCM_GUARD_ROCM_ALGORITHM_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif // ROCM_GUARD_ROCM_ALGORITHM_HPP diff --git a/src/targets/gpu/kernels/include/rocm/algorithm/accumulate.hpp b/src/targets/gpu/kernels/include/rocm/algorithm/accumulate.hpp new file mode 100644 index 00000000000..6b971a11b34 --- /dev/null +++ b/src/targets/gpu/kernels/include/rocm/algorithm/accumulate.hpp @@ -0,0 +1,51 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2025-2026 Advanced Micro Devices, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#ifndef ROCM_GUARD_ROCM_ALGORITHM_ACCUMULATE_HPP +#define ROCM_GUARD_ROCM_ALGORITHM_ACCUMULATE_HPP + +#include + +namespace rocm { +inline namespace ROCM_INLINE_NS { + +template +constexpr T accumulate(InputIt first, InputIt last, T init, BinaryOperation op) +{ + for(; first != last; ++first) + { + init = op(static_cast(init), *first); + } + return init; +} + +template +constexpr T accumulate(InputIt first, InputIt last, T init) +{ + return accumulate(first, last, init, [](auto x, auto y) { return x + y; }); +} + +} // namespace ROCM_INLINE_NS +} // namespace rocm +#endif // ROCM_GUARD_ROCM_ALGORITHM_ACCUMULATE_HPP diff --git a/src/targets/gpu/kernels/include/rocm/algorithm/all_of.hpp b/src/targets/gpu/kernels/include/rocm/algorithm/all_of.hpp new file mode 100644 index 00000000000..ba3b8000db0 --- /dev/null +++ b/src/targets/gpu/kernels/include/rocm/algorithm/all_of.hpp @@ -0,0 +1,42 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2025-2026 Advanced Micro Devices, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#ifndef ROCM_GUARD_ROCM_ALGORITHM_ALL_OF_HPP +#define ROCM_GUARD_ROCM_ALGORITHM_ALL_OF_HPP + +#include +#include + +namespace rocm { +inline namespace ROCM_INLINE_NS { + +template +constexpr bool all_of(InputIt first, InputIt last, UnaryPredicate p) +{ + return none_of(first, last, [=](auto&& x) { return not p(x); }); +} + +} // namespace ROCM_INLINE_NS +} // namespace rocm +#endif // ROCM_GUARD_ROCM_ALGORITHM_ALL_OF_HPP diff --git a/src/targets/gpu/kernels/include/rocm/algorithm/any_of.hpp b/src/targets/gpu/kernels/include/rocm/algorithm/any_of.hpp new file mode 100644 index 00000000000..a818a3c5970 --- /dev/null +++ b/src/targets/gpu/kernels/include/rocm/algorithm/any_of.hpp @@ -0,0 +1,42 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2025-2026 Advanced Micro Devices, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#ifndef ROCM_GUARD_ROCM_ALGORITHM_ANY_OF_HPP +#define ROCM_GUARD_ROCM_ALGORITHM_ANY_OF_HPP + +#include +#include + +namespace rocm { +inline namespace ROCM_INLINE_NS { + +template +constexpr bool any_of(InputIt first, InputIt last, UnaryPredicate p) +{ + return find_if(first, last, p) != last; +} + +} // namespace ROCM_INLINE_NS +} // namespace rocm +#endif // ROCM_GUARD_ROCM_ALGORITHM_ANY_OF_HPP diff --git a/src/targets/gpu/kernels/include/rocm/algorithm/copy.hpp b/src/targets/gpu/kernels/include/rocm/algorithm/copy.hpp new file mode 100644 index 00000000000..14bfebf14fe --- /dev/null +++ b/src/targets/gpu/kernels/include/rocm/algorithm/copy.hpp @@ -0,0 +1,45 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2025-2026 Advanced Micro Devices, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#ifndef ROCM_GUARD_ROCM_ALGORITHM_COPY_HPP +#define ROCM_GUARD_ROCM_ALGORITHM_COPY_HPP + +#include + +namespace rocm { +inline namespace ROCM_INLINE_NS { + +template +constexpr OutputIt copy(InputIt first, InputIt last, OutputIt d_first) +{ + while(first != last) + { + *d_first++ = *first++; + } + return d_first; +} + +} // namespace ROCM_INLINE_NS +} // namespace rocm +#endif // ROCM_GUARD_ROCM_ALGORITHM_COPY_HPP diff --git a/src/targets/gpu/kernels/include/rocm/algorithm/copy_if.hpp b/src/targets/gpu/kernels/include/rocm/algorithm/copy_if.hpp new file mode 100644 index 00000000000..20af9370cd1 --- /dev/null +++ b/src/targets/gpu/kernels/include/rocm/algorithm/copy_if.hpp @@ -0,0 +1,49 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2025-2026 Advanced Micro Devices, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#ifndef ROCM_GUARD_ROCM_ALGORITHM_COPY_IF_HPP +#define ROCM_GUARD_ROCM_ALGORITHM_COPY_IF_HPP + +#include + +namespace rocm { +inline namespace ROCM_INLINE_NS { + +template +constexpr OutputIt copy_if(InputIt first, InputIt last, OutputIt d_first, UnaryPredicate pred) +{ + for(; first != last; ++first) + { + if(pred(*first)) + { + *d_first = *first; + ++d_first; + } + } + return d_first; +} + +} // namespace ROCM_INLINE_NS +} // namespace rocm +#endif // ROCM_GUARD_ROCM_ALGORITHM_COPY_IF_HPP diff --git a/src/targets/gpu/kernels/include/rocm/algorithm/equal.hpp b/src/targets/gpu/kernels/include/rocm/algorithm/equal.hpp new file mode 100644 index 00000000000..41424ca9128 --- /dev/null +++ b/src/targets/gpu/kernels/include/rocm/algorithm/equal.hpp @@ -0,0 +1,52 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2025-2026 Advanced Micro Devices, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#ifndef ROCM_GUARD_ROCM_ALGORITHM_EQUAL_HPP +#define ROCM_GUARD_ROCM_ALGORITHM_EQUAL_HPP + +#include + +namespace rocm { +inline namespace ROCM_INLINE_NS { + +template +constexpr bool equal(Iterator1 first1, Iterator1 last1, Iterator2 first2, BinaryPred p) +{ + for(; first1 != last1; ++first1, ++first2) + if(not p(*first1, *first2)) + { + return false; + } + return true; +} + +template +constexpr bool equal(Iterator1 first1, Iterator1 last1, Iterator2 first2) +{ + return equal(first1, last1, first2, [](auto&& x, auto&& y) { return x == y; }); +} + +} // namespace ROCM_INLINE_NS +} // namespace rocm +#endif // ROCM_GUARD_ROCM_ALGORITHM_EQUAL_HPP diff --git a/src/targets/gpu/kernels/include/rocm/algorithm/fill.hpp b/src/targets/gpu/kernels/include/rocm/algorithm/fill.hpp new file mode 100644 index 00000000000..a245d9574ad --- /dev/null +++ b/src/targets/gpu/kernels/include/rocm/algorithm/fill.hpp @@ -0,0 +1,42 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2025-2026 Advanced Micro Devices, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#ifndef ROCM_GUARD_ROCM_ALGORITHM_FILL_HPP +#define ROCM_GUARD_ROCM_ALGORITHM_FILL_HPP + +#include + +namespace rocm { +inline namespace ROCM_INLINE_NS { + +template +constexpr void fill(Iterator first, Iterator last, const T& value) +{ + for(; first != last; ++first) + *first = value; +} + +} // namespace ROCM_INLINE_NS +} // namespace rocm +#endif // ROCM_GUARD_ROCM_ALGORITHM_FILL_HPP diff --git a/src/targets/gpu/kernels/include/rocm/algorithm/find.hpp b/src/targets/gpu/kernels/include/rocm/algorithm/find.hpp new file mode 100644 index 00000000000..4cf15883b22 --- /dev/null +++ b/src/targets/gpu/kernels/include/rocm/algorithm/find.hpp @@ -0,0 +1,42 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2025-2026 Advanced Micro Devices, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#ifndef ROCM_GUARD_ROCM_ALGORITHM_FIND_HPP +#define ROCM_GUARD_ROCM_ALGORITHM_FIND_HPP + +#include +#include + +namespace rocm { +inline namespace ROCM_INLINE_NS { + +template +constexpr Iterator find(Iterator first, Iterator last, const T& value) +{ + return find_if(first, last, [&](const auto& x) { return x == value; }); +} + +} // namespace ROCM_INLINE_NS +} // namespace rocm +#endif // ROCM_GUARD_ROCM_ALGORITHM_FIND_HPP diff --git a/src/targets/gpu/kernels/include/rocm/algorithm/find_if.hpp b/src/targets/gpu/kernels/include/rocm/algorithm/find_if.hpp new file mode 100644 index 00000000000..cbb8ea663a3 --- /dev/null +++ b/src/targets/gpu/kernels/include/rocm/algorithm/find_if.hpp @@ -0,0 +1,48 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2025-2026 Advanced Micro Devices, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#ifndef ROCM_GUARD_ROCM_ALGORITHM_FIND_IF_HPP +#define ROCM_GUARD_ROCM_ALGORITHM_FIND_IF_HPP + +#include + +namespace rocm { +inline namespace ROCM_INLINE_NS { + +template +constexpr Iterator find_if(Iterator first, Iterator last, Predicate p) +{ + for(; first != last; ++first) + { + if(p(*first)) + { + return first; + } + } + return last; +} + +} // namespace ROCM_INLINE_NS +} // namespace rocm +#endif // ROCM_GUARD_ROCM_ALGORITHM_FIND_IF_HPP diff --git a/src/targets/gpu/kernels/include/rocm/algorithm/for_each.hpp b/src/targets/gpu/kernels/include/rocm/algorithm/for_each.hpp new file mode 100644 index 00000000000..28eff1373d6 --- /dev/null +++ b/src/targets/gpu/kernels/include/rocm/algorithm/for_each.hpp @@ -0,0 +1,45 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2025-2026 Advanced Micro Devices, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#ifndef ROCM_GUARD_ROCM_ALGORITHM_FOR_EACH_HPP +#define ROCM_GUARD_ROCM_ALGORITHM_FOR_EACH_HPP + +#include + +namespace rocm { +inline namespace ROCM_INLINE_NS { + +template +constexpr F for_each(Iterator first, Iterator last, F f) +{ + for(; first != last; ++first) + { + f(*first); + } + return f; +} + +} // namespace ROCM_INLINE_NS +} // namespace rocm +#endif // ROCM_GUARD_ROCM_ALGORITHM_FOR_EACH_HPP diff --git a/src/targets/gpu/kernels/include/rocm/algorithm/inner_product.hpp b/src/targets/gpu/kernels/include/rocm/algorithm/inner_product.hpp new file mode 100644 index 00000000000..790e2bb4809 --- /dev/null +++ b/src/targets/gpu/kernels/include/rocm/algorithm/inner_product.hpp @@ -0,0 +1,64 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2025-2026 Advanced Micro Devices, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#ifndef ROCM_GUARD_ROCM_ALGORITHM_INNER_PRODUCT_HPP +#define ROCM_GUARD_ROCM_ALGORITHM_INNER_PRODUCT_HPP + +#include + +namespace rocm { +inline namespace ROCM_INLINE_NS { + +template +constexpr T inner_product(InputIt1 first1, + InputIt1 last1, + InputIt2 first2, + T init, + BinaryOperation1 op1, + BinaryOperation2 op2) +{ + while(first1 != last1) + { + init = op1(init, op2(*first1, *first2)); + ++first1; + ++first2; + } + return init; +} + +template +constexpr T inner_product(InputIt1 first1, InputIt1 last1, InputIt2 first2, T init) +{ + return inner_product( + first1, + last1, + first2, + init, + [](auto x, auto y) { return x + y; }, + [](auto x, auto y) { return x * y; }); +} + +} // namespace ROCM_INLINE_NS +} // namespace rocm +#endif // ROCM_GUARD_ROCM_ALGORITHM_INNER_PRODUCT_HPP diff --git a/src/targets/gpu/kernels/include/rocm/algorithm/iota.hpp b/src/targets/gpu/kernels/include/rocm/algorithm/iota.hpp new file mode 100644 index 00000000000..1169f2a38fc --- /dev/null +++ b/src/targets/gpu/kernels/include/rocm/algorithm/iota.hpp @@ -0,0 +1,42 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2025-2026 Advanced Micro Devices, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#ifndef ROCM_GUARD_ROCM_ALGORITHM_IOTA_HPP +#define ROCM_GUARD_ROCM_ALGORITHM_IOTA_HPP + +#include + +namespace rocm { +inline namespace ROCM_INLINE_NS { + +template +constexpr void iota(Iterator first, Iterator last, T value) +{ + for(; first != last; ++first, ++value) + *first = value; +} + +} // namespace ROCM_INLINE_NS +} // namespace rocm +#endif // ROCM_GUARD_ROCM_ALGORITHM_IOTA_HPP diff --git a/src/targets/gpu/kernels/include/rocm/algorithm/is_sorted.hpp b/src/targets/gpu/kernels/include/rocm/algorithm/is_sorted.hpp new file mode 100644 index 00000000000..88357cdfdad --- /dev/null +++ b/src/targets/gpu/kernels/include/rocm/algorithm/is_sorted.hpp @@ -0,0 +1,49 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2025-2026 Advanced Micro Devices, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#ifndef ROCM_GUARD_ROCM_ALGORITHM_IS_SORTED_HPP +#define ROCM_GUARD_ROCM_ALGORITHM_IS_SORTED_HPP + +#include +#include +#include + +namespace rocm { +inline namespace ROCM_INLINE_NS { + +template +constexpr bool is_sorted(Iterator first, Iterator last, Compare comp) +{ + return is_sorted_until(first, last, comp) == last; +} + +template +constexpr bool is_sorted(Iterator first, Iterator last) +{ + return is_sorted(first, last, less<>{}); +} + +} // namespace ROCM_INLINE_NS +} // namespace rocm +#endif // ROCM_GUARD_ROCM_ALGORITHM_IS_SORTED_HPP diff --git a/src/targets/gpu/kernels/include/rocm/algorithm/is_sorted_until.hpp b/src/targets/gpu/kernels/include/rocm/algorithm/is_sorted_until.hpp new file mode 100644 index 00000000000..c1730d36e30 --- /dev/null +++ b/src/targets/gpu/kernels/include/rocm/algorithm/is_sorted_until.hpp @@ -0,0 +1,58 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2025-2026 Advanced Micro Devices, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#ifndef ROCM_GUARD_ROCM_ALGORITHM_IS_SORTED_UNTIL_HPP +#define ROCM_GUARD_ROCM_ALGORITHM_IS_SORTED_UNTIL_HPP + +#include +#include + +namespace rocm { +inline namespace ROCM_INLINE_NS { + +template +constexpr Iterator is_sorted_until(Iterator first, Iterator last, Compare comp) +{ + if(first != last) + { + Iterator next = first; + while(++next != last) + { + if(comp(*next, *first)) + return next; + first = next; + } + } + return last; +} + +template +constexpr Iterator is_sorted_until(Iterator first, Iterator last) +{ + return is_sorted_until(first, last, less<>{}); +} + +} // namespace ROCM_INLINE_NS +} // namespace rocm +#endif // ROCM_GUARD_ROCM_ALGORITHM_IS_SORTED_UNTIL_HPP diff --git a/src/targets/gpu/kernels/include/rocm/algorithm/iter_swap.hpp b/src/targets/gpu/kernels/include/rocm/algorithm/iter_swap.hpp new file mode 100644 index 00000000000..75b5e19db72 --- /dev/null +++ b/src/targets/gpu/kernels/include/rocm/algorithm/iter_swap.hpp @@ -0,0 +1,44 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2025-2026 Advanced Micro Devices, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#ifndef ROCM_GUARD_ROCM_ALGORITHM_ITER_SWAP_HPP +#define ROCM_GUARD_ROCM_ALGORITHM_ITER_SWAP_HPP + +#include +#include + +namespace rocm { +inline namespace ROCM_INLINE_NS { + +template +constexpr void iter_swap(Iterator1 a, Iterator2 b) +{ + if(a == b) + return; + swap(*a, *b); +} + +} // namespace ROCM_INLINE_NS +} // namespace rocm +#endif // ROCM_GUARD_ROCM_ALGORITHM_ITER_SWAP_HPP diff --git a/src/targets/gpu/kernels/include/rocm/algorithm/lower_bound.hpp b/src/targets/gpu/kernels/include/rocm/algorithm/lower_bound.hpp new file mode 100644 index 00000000000..42f9af124ab --- /dev/null +++ b/src/targets/gpu/kernels/include/rocm/algorithm/lower_bound.hpp @@ -0,0 +1,49 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2025-2026 Advanced Micro Devices, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#ifndef ROCM_GUARD_ROCM_ALGORITHM_LOWER_BOUND_HPP +#define ROCM_GUARD_ROCM_ALGORITHM_LOWER_BOUND_HPP + +#include +#include +#include + +namespace rocm { +inline namespace ROCM_INLINE_NS { + +template +constexpr Iterator lower_bound(Iterator first, Iterator last, const T& value, Compare comp) +{ + return upper_bound(first, last, value, [&](auto&& a, auto&& b) { return not comp(b, a); }); +} + +template +constexpr Iterator lower_bound(Iterator first, Iterator last, const T& value) +{ + return lower_bound(first, last, value, less<>{}); +} + +} // namespace ROCM_INLINE_NS +} // namespace rocm +#endif // ROCM_GUARD_ROCM_ALGORITHM_LOWER_BOUND_HPP diff --git a/src/targets/gpu/kernels/include/rocm/algorithm/max_element.hpp b/src/targets/gpu/kernels/include/rocm/algorithm/max_element.hpp new file mode 100644 index 00000000000..ee88f3e1315 --- /dev/null +++ b/src/targets/gpu/kernels/include/rocm/algorithm/max_element.hpp @@ -0,0 +1,49 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2025-2026 Advanced Micro Devices, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#ifndef ROCM_GUARD_ROCM_ALGORITHM_MAX_ELEMENT_HPP +#define ROCM_GUARD_ROCM_ALGORITHM_MAX_ELEMENT_HPP + +#include +#include +#include + +namespace rocm { +inline namespace ROCM_INLINE_NS { + +template +constexpr Iterator max_element(Iterator first, Iterator last, Compare comp) +{ + return min_element(first, last, [&](auto&& a, auto&& b) { return comp(b, a); }); +} + +template +constexpr Iterator max_element(Iterator first, Iterator last) +{ + return max_element(first, last, less<>{}); +} + +} // namespace ROCM_INLINE_NS +} // namespace rocm +#endif // ROCM_GUARD_ROCM_ALGORITHM_MAX_ELEMENT_HPP diff --git a/src/targets/gpu/kernels/include/rocm/algorithm/merge.hpp b/src/targets/gpu/kernels/include/rocm/algorithm/merge.hpp new file mode 100644 index 00000000000..223ed759d7b --- /dev/null +++ b/src/targets/gpu/kernels/include/rocm/algorithm/merge.hpp @@ -0,0 +1,63 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2025-2026 Advanced Micro Devices, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#ifndef ROCM_GUARD_ROCM_ALGORITHM_MERGE_HPP +#define ROCM_GUARD_ROCM_ALGORITHM_MERGE_HPP + +#include +#include + +namespace rocm { +inline namespace ROCM_INLINE_NS { + +template +constexpr OutputIterator merge(Iterator1 first1, + Iterator1 last1, + Iterator2 first2, + Iterator2 last2, + OutputIterator d_first, + Compare comp) +{ + for(; first1 != last1; ++d_first) + { + if(first2 == last2) + return copy(first1, last1, d_first); + + if(comp(*first2, *first1)) + { + *d_first = *first2; + ++first2; + } + else + { + *d_first = *first1; + ++first1; + } + } + return copy(first2, last2, d_first); +} + +} // namespace ROCM_INLINE_NS +} // namespace rocm +#endif // ROCM_GUARD_ROCM_ALGORITHM_MERGE_HPP diff --git a/src/targets/gpu/kernels/include/rocm/algorithm/min_element.hpp b/src/targets/gpu/kernels/include/rocm/algorithm/min_element.hpp new file mode 100644 index 00000000000..9c7b22a84b1 --- /dev/null +++ b/src/targets/gpu/kernels/include/rocm/algorithm/min_element.hpp @@ -0,0 +1,57 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2025-2026 Advanced Micro Devices, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#ifndef ROCM_GUARD_ROCM_ALGORITHM_MIN_ELEMENT_HPP +#define ROCM_GUARD_ROCM_ALGORITHM_MIN_ELEMENT_HPP + +#include +#include + +namespace rocm { +inline namespace ROCM_INLINE_NS { + +template +constexpr Iterator min_element(Iterator first, Iterator last, Compare comp) +{ + if(first == last) + return last; + + Iterator smallest = first; + + while(++first != last) + if(comp(*first, *smallest)) + smallest = first; + + return smallest; +} + +template +constexpr Iterator min_element(Iterator first, Iterator last) +{ + return min_element(first, last, less<>{}); +} + +} // namespace ROCM_INLINE_NS +} // namespace rocm +#endif // ROCM_GUARD_ROCM_ALGORITHM_MIN_ELEMENT_HPP diff --git a/src/targets/gpu/kernels/include/rocm/algorithm/none_of.hpp b/src/targets/gpu/kernels/include/rocm/algorithm/none_of.hpp new file mode 100644 index 00000000000..226cdda9296 --- /dev/null +++ b/src/targets/gpu/kernels/include/rocm/algorithm/none_of.hpp @@ -0,0 +1,42 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2025-2026 Advanced Micro Devices, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#ifndef ROCM_GUARD_ROCM_ALGORITHM_NONE_OF_HPP +#define ROCM_GUARD_ROCM_ALGORITHM_NONE_OF_HPP + +#include +#include + +namespace rocm { +inline namespace ROCM_INLINE_NS { + +template +constexpr bool none_of(InputIt first, InputIt last, UnaryPredicate p) +{ + return find_if(first, last, p) == last; +} + +} // namespace ROCM_INLINE_NS +} // namespace rocm +#endif // ROCM_GUARD_ROCM_ALGORITHM_NONE_OF_HPP diff --git a/src/targets/gpu/kernels/include/rocm/algorithm/rotate.hpp b/src/targets/gpu/kernels/include/rocm/algorithm/rotate.hpp new file mode 100644 index 00000000000..b572f771a88 --- /dev/null +++ b/src/targets/gpu/kernels/include/rocm/algorithm/rotate.hpp @@ -0,0 +1,59 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2025-2026 Advanced Micro Devices, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#ifndef ROCM_GUARD_ROCM_ALGORITHM_ROTATE_HPP +#define ROCM_GUARD_ROCM_ALGORITHM_ROTATE_HPP + +#include +#include + +namespace rocm { +inline namespace ROCM_INLINE_NS { + +template +constexpr Iterator rotate(Iterator first, Iterator middle, Iterator last) +{ + if(first == middle) + return last; + + if(middle == last) + return first; + + Iterator write = first; + Iterator next_read = first; + + for(Iterator read = middle; read != last; ++write, ++read) + { + if(write == next_read) + next_read = read; + iter_swap(write, read); + } + + rotate(write, next_read, last); + return write; +} + +} // namespace ROCM_INLINE_NS +} // namespace rocm +#endif // ROCM_GUARD_ROCM_ALGORITHM_ROTATE_HPP diff --git a/src/targets/gpu/kernels/include/rocm/algorithm/search.hpp b/src/targets/gpu/kernels/include/rocm/algorithm/search.hpp new file mode 100644 index 00000000000..26c9c2848d8 --- /dev/null +++ b/src/targets/gpu/kernels/include/rocm/algorithm/search.hpp @@ -0,0 +1,66 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2025-2026 Advanced Micro Devices, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#ifndef ROCM_GUARD_ROCM_ALGORITHM_SEARCH_HPP +#define ROCM_GUARD_ROCM_ALGORITHM_SEARCH_HPP + +#include + +namespace rocm { +inline namespace ROCM_INLINE_NS { + +template +constexpr Iterator1 +search(Iterator1 first, Iterator1 last, Iterator2 s_first, Iterator2 s_last, BinaryPredicate pred) +{ + for(;; ++first) + { + Iterator1 it = first; + for(Iterator2 s_it = s_first;; ++it, ++s_it) + { + if(s_it == s_last) + { + return first; + } + if(it == last) + { + return last; + } + if(not pred(*it, *s_it)) + { + break; + } + } + } +} + +template +constexpr Iterator1 search(Iterator1 first, Iterator1 last, Iterator2 s_first, Iterator2 s_last) +{ + return search(first, last, s_first, s_last, [](auto&& x, auto&& y) { return x == y; }); +} + +} // namespace ROCM_INLINE_NS +} // namespace rocm +#endif // ROCM_GUARD_ROCM_ALGORITHM_SEARCH_HPP diff --git a/src/targets/gpu/kernels/include/rocm/algorithm/sort.hpp b/src/targets/gpu/kernels/include/rocm/algorithm/sort.hpp new file mode 100644 index 00000000000..a26a6672602 --- /dev/null +++ b/src/targets/gpu/kernels/include/rocm/algorithm/sort.hpp @@ -0,0 +1,56 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2025-2026 Advanced Micro Devices, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#ifndef ROCM_GUARD_ROCM_ALGORITHM_SORT_HPP +#define ROCM_GUARD_ROCM_ALGORITHM_SORT_HPP + +#include +#include +#include +#include +#include +#include + +namespace rocm { +inline namespace ROCM_INLINE_NS { + +template +constexpr void sort(Iterator first, Iterator last, Compare comp) +{ + if(first == last) + return; + for(auto i = first; i != last - 1; ++i) + iter_swap(i, min_element(i, last, comp)); + ROCM_ASSERT(is_sorted(first, last, comp)); +} + +template +constexpr void sort(Iterator first, Iterator last) +{ + sort(first, last, less<>{}); +} + +} // namespace ROCM_INLINE_NS +} // namespace rocm +#endif // ROCM_GUARD_ROCM_ALGORITHM_SORT_HPP diff --git a/src/targets/gpu/kernels/include/rocm/algorithm/stable_sort.hpp b/src/targets/gpu/kernels/include/rocm/algorithm/stable_sort.hpp new file mode 100644 index 00000000000..a24b5a9c3f0 --- /dev/null +++ b/src/targets/gpu/kernels/include/rocm/algorithm/stable_sort.hpp @@ -0,0 +1,56 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2025-2026 Advanced Micro Devices, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#ifndef ROCM_GUARD_ROCM_ALGORITHM_STABLE_SORT_HPP +#define ROCM_GUARD_ROCM_ALGORITHM_STABLE_SORT_HPP + +#include +#include +#include +#include +#include +#include + +namespace rocm { +inline namespace ROCM_INLINE_NS { + +template +constexpr void stable_sort(Iterator first, Iterator last, Compare comp) +{ + if(first == last) + return; + for(auto i = first; i != last; ++i) + rotate(upper_bound(first, i, *i, comp), i, i + 1); + ROCM_ASSERT(is_sorted(first, last, comp)); +} + +template +constexpr void stable_sort(Iterator first, Iterator last) +{ + stable_sort(first, last, less<>{}); +} + +} // namespace ROCM_INLINE_NS +} // namespace rocm +#endif // ROCM_GUARD_ROCM_ALGORITHM_STABLE_SORT_HPP diff --git a/src/targets/gpu/kernels/include/rocm/algorithm/transform.hpp b/src/targets/gpu/kernels/include/rocm/algorithm/transform.hpp new file mode 100644 index 00000000000..526ec8b8107 --- /dev/null +++ b/src/targets/gpu/kernels/include/rocm/algorithm/transform.hpp @@ -0,0 +1,55 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2025-2026 Advanced Micro Devices, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#ifndef ROCM_GUARD_ROCM_ALGORITHM_TRANSFORM_HPP +#define ROCM_GUARD_ROCM_ALGORITHM_TRANSFORM_HPP + +#include + +namespace rocm { +inline namespace ROCM_INLINE_NS { + +template +constexpr OutputIterator +transform(Iterator first1, Iterator last1, OutputIterator out, UnaryOp unary_op) +{ + for(; first1 != last1; ++out, ++first1) + *out = unary_op(*first1); + + return out; +} + +template +constexpr OutputIterator transform( + Iterator1 first1, Iterator1 last1, Iterator2 first2, OutputIterator out, BinaryOp binary_op) +{ + for(; first1 != last1; ++out, ++first1, ++first2) + *out = binary_op(*first1, *first2); + + return out; +} + +} // namespace ROCM_INLINE_NS +} // namespace rocm +#endif // ROCM_GUARD_ROCM_ALGORITHM_TRANSFORM_HPP diff --git a/src/targets/gpu/kernels/include/rocm/algorithm/upper_bound.hpp b/src/targets/gpu/kernels/include/rocm/algorithm/upper_bound.hpp new file mode 100644 index 00000000000..27117d622a3 --- /dev/null +++ b/src/targets/gpu/kernels/include/rocm/algorithm/upper_bound.hpp @@ -0,0 +1,66 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2025-2026 Advanced Micro Devices, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#ifndef ROCM_GUARD_ROCM_ALGORITHM_UPPER_BOUND_HPP +#define ROCM_GUARD_ROCM_ALGORITHM_UPPER_BOUND_HPP + +#include +#include + +namespace rocm { +inline namespace ROCM_INLINE_NS { + +template +constexpr Iterator upper_bound(Iterator first, Iterator last, const T& value, Compare comp) +{ + auto count = last - first; + + while(count > 0) + { + // NOLINTNEXTLINE(readability-qualified-auto) + auto it = first; + auto step = count / 2; + it += step; + + if(not comp(value, *it)) + { + first = ++it; + count -= step + 1; + } + else + count = step; + } + + return first; +} + +template +constexpr Iterator upper_bound(Iterator first, Iterator last, const T& value) +{ + return upper_bound(first, last, value, less<>{}); +} + +} // namespace ROCM_INLINE_NS +} // namespace rocm +#endif // ROCM_GUARD_ROCM_ALGORITHM_UPPER_BOUND_HPP diff --git a/src/targets/gpu/kernels/include/rocm/array.hpp b/src/targets/gpu/kernels/include/rocm/array.hpp new file mode 100644 index 00000000000..8d689a5c963 --- /dev/null +++ b/src/targets/gpu/kernels/include/rocm/array.hpp @@ -0,0 +1,245 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2025-2026 Advanced Micro Devices, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#ifndef ROCM_GUARD_ROCM_ARRAY_HPP +#define ROCM_GUARD_ROCM_ARRAY_HPP + +#include +#include +#include +#include +#include +#include + +namespace rocm { +inline namespace ROCM_INLINE_NS { + +template +struct array +{ + using value_type = T; + using pointer = T*; + using const_pointer = const T*; + using reference = T&; + using const_reference = const T&; + using size_type = size_t; + using difference_type = ptrdiff_t; + using iterator = T*; + using const_iterator = const T*; + using reverse_iterator = rocm::reverse_iterator; + using const_reverse_iterator = rocm::reverse_iterator; + + T elems[N]; // NOLINT + + // fill + constexpr void fill(const T& u) + { + // This is the device-side reimplementation that std::fill would call into. + // cppcheck-suppress useStlAlgorithm + for(size_type i = 0; i < N; ++i) + elems[i] = u; + } + + // swap + constexpr void swap(array& other) noexcept + { + for(size_type i = 0; i < N; ++i) + rocm::swap(elems[i], other.elems[i]); + } + + // iterators + constexpr iterator begin() noexcept { return elems; } + constexpr const_iterator begin() const noexcept { return elems; } + constexpr iterator end() noexcept { return elems + N; } + constexpr const_iterator end() const noexcept { return elems + N; } + + constexpr reverse_iterator rbegin() noexcept { return reverse_iterator(end()); } + constexpr const_reverse_iterator rbegin() const noexcept + { + return const_reverse_iterator(end()); + } + constexpr reverse_iterator rend() noexcept { return reverse_iterator(begin()); } + constexpr const_reverse_iterator rend() const noexcept + { + return const_reverse_iterator(begin()); + } + + constexpr const_iterator cbegin() const noexcept { return begin(); } + constexpr const_iterator cend() const noexcept { return end(); } + constexpr const_reverse_iterator crbegin() const noexcept { return rbegin(); } + constexpr const_reverse_iterator crend() const noexcept { return rend(); } + + // capacity + constexpr size_type size() const noexcept { return N; } + constexpr size_type max_size() const noexcept { return N; } + constexpr bool empty() const noexcept { return N == 0; } + + // element access + constexpr reference operator[](size_type n) { return elems[n]; } + constexpr const_reference operator[](size_type n) const { return elems[n]; } + + constexpr reference at(size_type n) { return elems[n]; } + constexpr const_reference at(size_type n) const { return elems[n]; } + + constexpr reference front() { return elems[0]; } + constexpr const_reference front() const { return elems[0]; } + constexpr reference back() { return elems[N - 1]; } + constexpr const_reference back() const { return elems[N - 1]; } + + constexpr T* data() noexcept { return elems; } + constexpr const T* data() const noexcept { return elems; } + + // comparison operators + friend constexpr bool operator==(const array& x, const array& y) + { + for(size_type i = 0; i < N; ++i) + { + if(not(x.elems[i] == y.elems[i])) + return false; + } + return true; + } + + friend constexpr bool operator!=(const array& x, const array& y) { return not(x == y); } + + friend constexpr bool operator<(const array& x, const array& y) + { + for(size_type i = 0; i < N; ++i) + { + if(x.elems[i] < y.elems[i]) + return true; + if(y.elems[i] < x.elems[i]) + return false; + } + return false; + } + + friend constexpr bool operator>(const array& x, const array& y) { return y < x; } + + friend constexpr bool operator<=(const array& x, const array& y) { return not(y < x); } + + friend constexpr bool operator>=(const array& x, const array& y) { return not(x < y); } +}; + +// zero-size specialization +template +struct array +{ + using value_type = T; + using pointer = T*; + using const_pointer = const T*; + using reference = T&; + using const_reference = const T&; + using size_type = size_t; + using difference_type = ptrdiff_t; + using iterator = T*; + using const_iterator = const T*; + using reverse_iterator = rocm::reverse_iterator; + using const_reverse_iterator = rocm::reverse_iterator; + + constexpr void fill(const T&) {} + constexpr void swap(array&) noexcept {} + + constexpr iterator begin() noexcept { return nullptr; } + constexpr const_iterator begin() const noexcept { return nullptr; } + constexpr iterator end() noexcept { return nullptr; } + constexpr const_iterator end() const noexcept { return nullptr; } + + constexpr reverse_iterator rbegin() noexcept { return reverse_iterator(end()); } + constexpr const_reverse_iterator rbegin() const noexcept + { + return const_reverse_iterator(end()); + } + constexpr reverse_iterator rend() noexcept { return reverse_iterator(begin()); } + constexpr const_reverse_iterator rend() const noexcept + { + return const_reverse_iterator(begin()); + } + + constexpr const_iterator cbegin() const noexcept { return begin(); } + constexpr const_iterator cend() const noexcept { return end(); } + constexpr const_reverse_iterator crbegin() const noexcept { return rbegin(); } + constexpr const_reverse_iterator crend() const noexcept { return rend(); } + + constexpr size_type size() const noexcept { return 0; } + constexpr size_type max_size() const noexcept { return 0; } + constexpr bool empty() const noexcept { return true; } + + constexpr T* data() noexcept { return nullptr; } + constexpr const T* data() const noexcept { return nullptr; } + + friend constexpr bool operator==(const array&, const array&) { return true; } + friend constexpr bool operator!=(const array&, const array&) { return false; } + friend constexpr bool operator<(const array&, const array&) { return false; } + friend constexpr bool operator>(const array&, const array&) { return false; } + friend constexpr bool operator<=(const array&, const array&) { return true; } + friend constexpr bool operator>=(const array&, const array&) { return true; } +}; + +// CTAD +template +ROCM_HIP_HOST_DEVICE_DEDUCTION_GUIDE array(T, U...) -> array; + +// swap +template +constexpr void swap(array& x, array& y) noexcept(noexcept(x.swap(y))) +{ + x.swap(y); +} + +// to_array +namespace detail { + +template +constexpr array, N> to_array_lvalue(T (&a)[N], rocm::index_sequence) // NOLINT +{ + return {{a[Is]...}}; +} + +template +constexpr array, N> +// NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved) +to_array_rvalue(T (&&a)[N], rocm::index_sequence) // NOLINT +{ + return {{static_cast(a[Is])...}}; +} + +} // namespace detail + +template +constexpr array, N> to_array(T (&a)[N]) // NOLINT +{ + return detail::to_array_lvalue(a, rocm::make_index_sequence{}); +} + +template +constexpr array, N> to_array(T (&&a)[N]) // NOLINT +{ + return detail::to_array_rvalue(static_cast(a), + rocm::make_index_sequence{}); // NOLINT +} + +} // namespace ROCM_INLINE_NS +} // namespace rocm +#endif // ROCM_GUARD_ROCM_ARRAY_HPP diff --git a/src/targets/gpu/kernels/include/rocm/assert.hpp b/src/targets/gpu/kernels/include/rocm/assert.hpp new file mode 100644 index 00000000000..95a6375a2b9 --- /dev/null +++ b/src/targets/gpu/kernels/include/rocm/assert.hpp @@ -0,0 +1,181 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2025-2026 Advanced Micro Devices, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#ifndef ROCM_GUARD_ROCM_ASSERT_HPP +#define ROCM_GUARD_ROCM_ASSERT_HPP + +#include +#include + +#ifndef __HIPCC_RTC__ +#include +#include +#endif + +namespace rocm { +inline namespace ROCM_INLINE_NS { + +// Workaround hip's broken abort on device code +#ifdef __HIP_DEVICE_COMPILE__ +// NOLINTNEXTLINE +#define ROCM_HIP_NORETURN +#else +// NOLINTNEXTLINE +#define ROCM_HIP_NORETURN [[noreturn]] +#endif + +namespace debug { +struct swallow +{ + template + constexpr swallow(Ts&&...) + { + } +}; + +template +struct print_buffer +{ + char buffer[N + 1] = {0}; + char* pos = buffer; + + constexpr void append(char c) + { + if(c == 0) + return; + if(pos < buffer + N) + { + *pos = c; + pos++; + } + } + static constexpr void reverse(char* first, char* last) + { + if(first == last) + return; + last--; + while(first < last) + { + char tmp = *first; + *first = *last; + *last = tmp; + first++; + last--; + } + } + + template + constexpr void append(T i) + { + if(i < 0) + { + append('-'); + i = -i; + } + if(i == 0) + { + append('0'); + return; + } + char* start = pos; + while(i != 0) + { + char c = (i % 10) + '0'; + append(c); + i = i / 10; + } + reverse(start, pos); + } + + constexpr void append(const char* str) + { + if(str == nullptr) + return; + int i = 512; + while(*str != 0 and i > 0) + { + append(*str); + str++; + i--; + } + } + + template + constexpr void append(const char (&array)[M]) + { + for(int i = 0; i < M; i++) + append(array[i]); + } +}; + +template +ROCM_HIP_HOST_DEVICE void print(const Ts&... xs) +{ + print_buffer<1024> buffer; + swallow{(buffer.append(xs), 0)...}; + printf("%s", buffer.buffer); +} + +} // namespace debug + +// noreturn cannot be used on this function because abort in hip is broken +template +ROCM_HIP_NORETURN inline ROCM_HIP_HOST_DEVICE void +assert_fail(const T1& assertion, const T2& file, const T3& line, const T4& function) +{ + // printf is broken on hip with more than one argument, so use a simple print functions instead + debug::print(file, ":", line, ": ", function, ": assertion '", assertion, "' failed.\n"); + // printf("%s:%s: %s: assertion '%s' failed.\n", file, line, function, assertion); + abort(); +} + +// NOLINTNEXTLINE +#define ROCM_ASSERT_FAIL(cond, ...) \ + ((cond) ? void(0) : [](auto&&... private_migraphx_xs) { \ + assert_fail(private_migraphx_xs...); \ + }(__VA_ARGS__)) + +// NOLINTNEXTLINE +#define ROCM_CHECK(cond) ROCM_ASSERT_FAIL(cond, #cond, __FILE__, __LINE__, __PRETTY_FUNCTION__) + +#ifdef CPPCHECK +// NOLINTNEXTLINE +#define ROCM_ASSERT assert +#define ROCM_ASSUME assert +#define ROCM_UNREACHABLE() ROCM_ASSERT(false) +#elif defined(ROCM_DEBUG) +// NOLINTNEXTLINE +#define ROCM_ASSERT ROCM_CHECK +#define ROCM_ASSUME ROCM_CHECK +#define ROCM_UNREACHABLE() ROCM_ASSERT(false) +#else +// NOLINTNEXTLINE +#define ROCM_ASSUME __builtin_assume +#define ROCM_UNREACHABLE __builtin_unreachable +#define ROCM_ASSERT(cond) +#endif + +} // namespace ROCM_INLINE_NS +} // namespace rocm +#endif // ROCM_GUARD_ROCM_ASSERT_HPP diff --git a/src/targets/gpu/kernels/include/rocm/bit.hpp b/src/targets/gpu/kernels/include/rocm/bit.hpp new file mode 100644 index 00000000000..0bfedd33aa7 --- /dev/null +++ b/src/targets/gpu/kernels/include/rocm/bit.hpp @@ -0,0 +1,150 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2025-2026 Advanced Micro Devices, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#ifndef ROCM_GUARD_ROCM_BIT_HPP +#define ROCM_GUARD_ROCM_BIT_HPP + +#include +#include +#include +#include + +namespace rocm { +inline namespace ROCM_INLINE_NS { + +template {} and + rocm::is_trivially_copyable{} and sizeof(To) == sizeof(From))> +constexpr To bit_cast(From fr) noexcept +{ + return __builtin_bit_cast(To, fr); +} + +template {})> +constexpr int countl_zero(T x) noexcept +{ + return __builtin_clzg(x, numeric_limits::digits); +} + +template {})> +constexpr int countl_one(T x) noexcept +{ + return countl_zero(T(~x)); +} + +template {})> +constexpr int countr_zero(T x) noexcept +{ + return __builtin_ctzg(x, numeric_limits::digits); +} + +template {})> +constexpr int countr_one(T x) noexcept +{ + return countr_zero(T(~x)); +} + +template {})> +constexpr int popcount(T x) noexcept +{ + return __builtin_popcountg(x); +} + +template {})> +constexpr int bit_width(T x) noexcept +{ + return numeric_limits::digits - countl_zero(x); +} + +template {})> +constexpr T bit_floor(T x) noexcept +{ + if(x != 0) + { + unsigned shift = bit_width(x) - 1; + return T{1} << shift; + } + return 0; +} + +template {})> +constexpr T bit_ceil(T x) noexcept +{ + if(x <= 1) + return 1; + unsigned e = bit_width(T(x - 1)); + // cppcheck cannot resolve numeric_limits::digits for the dependent T and reads it as the + // primary template's 0, so it wrongly sees this as comparing an unsigned value against zero. + // cppcheck-suppress unsignedLessThanZero + ROCM_ASSERT(e < numeric_limits::digits); + if constexpr(is_same{}) + return T{1} << e; + constexpr unsigned offset_for_ub = numeric_limits::digits - numeric_limits::digits; + return 1u << (e + offset_for_ub) >> offset_for_ub; +} + +template {})> +constexpr bool has_single_bit(T x) noexcept +{ + return popcount(x) == 1; +} + +template {})> +constexpr T rotl(T x, int s) noexcept +{ + constexpr int n = numeric_limits::digits; + // cppcheck reads numeric_limits::digits as the primary template's 0 (it cannot resolve the + // specialization for the dependent T), so it wrongly flags this modulo as a division by zero + // and then treats the r == 0 test below as always false. + // cppcheck-suppress zerodiv + int r = s % n; + + // cppcheck-suppress knownConditionTrueFalse + if(r == 0) + return x; + + if(r > 0) + { + unsigned ur = r; + unsigned shift = n - r; + // NOLINTNEXTLINE(hicpp-signed-bitwise) + return (x << ur) | (x >> shift); + } + + unsigned ur = -r; + unsigned shift = n + r; + // NOLINTNEXTLINE(hicpp-signed-bitwise) + return (x >> ur) | (x << shift); +} + +template {})> +constexpr T rotr(T x, int s) noexcept +{ + return rotl(x, -s); +} + +} // namespace ROCM_INLINE_NS +} // namespace rocm +#endif // ROCM_GUARD_ROCM_BIT_HPP diff --git a/src/targets/gpu/kernels/include/rocm/config.hpp b/src/targets/gpu/kernels/include/rocm/config.hpp new file mode 100644 index 00000000000..82b9b4fca23 --- /dev/null +++ b/src/targets/gpu/kernels/include/rocm/config.hpp @@ -0,0 +1,50 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2015-2026 Advanced Micro Devices, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#ifndef ROCM_GUARD_ROCM_CONFIG_HPP +#define ROCM_GUARD_ROCM_CONFIG_HPP + +namespace rocm { + +#if !defined(ROCM_USE_CLANG_TIDY) +#define ROCM_INLINE_NS pocket_version_1 +#endif + +#ifdef __HIP_DEVICE_COMPILE__ +// NOLINTNEXTLINE +#define ROCM_HIP_HOST_DEVICE __host__ __device__ +#else +// NOLINTNEXTLINE +#define ROCM_HIP_HOST_DEVICE +#endif + +#ifdef MIGRAPHX_WORKAROUND_BROKEN_DEDUCTION_GUIDE +// NOLINTNEXTLINE +#define ROCM_HIP_HOST_DEVICE_DEDUCTION_GUIDE ROCM_HIP_HOST_DEVICE +#else +#define ROCM_HIP_HOST_DEVICE_DEDUCTION_GUIDE +#endif + +} // namespace rocm +#endif // ROCM_GUARD_ROCM_CONFIG_HPP diff --git a/src/targets/gpu/kernels/include/rocm/functional.hpp b/src/targets/gpu/kernels/include/rocm/functional.hpp new file mode 100644 index 00000000000..00b933b530d --- /dev/null +++ b/src/targets/gpu/kernels/include/rocm/functional.hpp @@ -0,0 +1,36 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2025-2026 Advanced Micro Devices, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#ifndef ROCM_GUARD_ROCM_FUNCTIONAL_HPP +#define ROCM_GUARD_ROCM_FUNCTIONAL_HPP + +#include +#include + +namespace rocm { +inline namespace ROCM_INLINE_NS { + +} // namespace ROCM_INLINE_NS +} // namespace rocm +#endif // ROCM_GUARD_ROCM_FUNCTIONAL_HPP diff --git a/src/targets/gpu/kernels/include/rocm/functional/operations.hpp b/src/targets/gpu/kernels/include/rocm/functional/operations.hpp new file mode 100644 index 00000000000..de54a4d862d --- /dev/null +++ b/src/targets/gpu/kernels/include/rocm/functional/operations.hpp @@ -0,0 +1,99 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2025-2026 Advanced Micro Devices, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#ifndef ROCM_GUARD_FUNCTIONAL_OPERATIONS_HPP +#define ROCM_GUARD_FUNCTIONAL_OPERATIONS_HPP + +#include + +namespace rocm { +inline namespace ROCM_INLINE_NS { + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define ROCM_FUNCTIONAL_BINARY_OP(name, op, result) \ + template \ + struct name \ + { \ + constexpr result operator()(const T& x, const T& y) const { return x op y; } \ + }; \ + template <> \ + struct name \ + { \ + using is_transparent = void; \ + template \ + constexpr auto operator()(T&& x, U&& y) const \ + noexcept(noexcept(static_cast(x) op static_cast(y))) \ + -> decltype(static_cast(x) op static_cast(y)) \ + { \ + return static_cast(x) op static_cast(y); \ + } \ + }; + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define ROCM_FUNCTIONAL_UNARY_OP(name, op, result) \ + template \ + struct name \ + { \ + constexpr result operator()(const T& x) const { return op x; } \ + }; \ + template <> \ + struct name \ + { \ + using is_transparent = void; \ + template \ + constexpr auto operator()(T&& x) const noexcept(noexcept(op static_cast(x))) \ + -> decltype(op static_cast(x)) \ + { \ + return op static_cast(x); \ + } \ + }; + +ROCM_FUNCTIONAL_BINARY_OP(plus, +, T) +ROCM_FUNCTIONAL_BINARY_OP(minus, -, T) +ROCM_FUNCTIONAL_BINARY_OP(multiplies, *, T) +ROCM_FUNCTIONAL_BINARY_OP(divides, /, T) +ROCM_FUNCTIONAL_BINARY_OP(modulus, %, T) +// NOLINTBEGIN(hicpp-signed-bitwise) +ROCM_FUNCTIONAL_BINARY_OP(bit_and, &, T) +ROCM_FUNCTIONAL_BINARY_OP(bit_or, |, T) +ROCM_FUNCTIONAL_BINARY_OP(bit_xor, ^, T) +// NOLINTEND(hicpp-signed-bitwise) + +ROCM_FUNCTIONAL_BINARY_OP(equal_to, ==, bool) +ROCM_FUNCTIONAL_BINARY_OP(not_equal_to, !=, bool) +ROCM_FUNCTIONAL_BINARY_OP(greater, >, bool) +ROCM_FUNCTIONAL_BINARY_OP(less, <, bool) +ROCM_FUNCTIONAL_BINARY_OP(greater_equal, >=, bool) +ROCM_FUNCTIONAL_BINARY_OP(less_equal, <=, bool) +ROCM_FUNCTIONAL_BINARY_OP(logical_and, and, bool) +ROCM_FUNCTIONAL_BINARY_OP(logical_or, or, bool) + +ROCM_FUNCTIONAL_UNARY_OP(negate, -, T) +ROCM_FUNCTIONAL_UNARY_OP(logical_not, not, bool) +// NOLINTNEXTLINE(hicpp-signed-bitwise) +ROCM_FUNCTIONAL_UNARY_OP(bit_not, ~, T) + +} // namespace ROCM_INLINE_NS +} // namespace rocm +#endif // MIGRAPHX_GUARD_FUNCTIONAL_OPERATIONS_HPP diff --git a/src/targets/gpu/kernels/include/rocm/integral_constant.hpp b/src/targets/gpu/kernels/include/rocm/integral_constant.hpp new file mode 100644 index 00000000000..9c40e768bba --- /dev/null +++ b/src/targets/gpu/kernels/include/rocm/integral_constant.hpp @@ -0,0 +1,99 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2015-2026 Advanced Micro Devices, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#ifndef ROCM_GUARD_ROCM_INTEGRAL_CONSTANT_HPP +#define ROCM_GUARD_ROCM_INTEGRAL_CONSTANT_HPP + +#include + +namespace rocm { +inline namespace ROCM_INLINE_NS { + +template +struct integral_constant +{ + static constexpr T value = V; + using value_type = T; + using type = integral_constant; + constexpr operator value_type() const noexcept { return value; } + constexpr value_type operator()() const noexcept { return value; } + static constexpr type to() { return {}; } +}; + +// NOLINTNEXTLINE +#define ROCM_INTEGRAL_CONSTANT_BINARY_OP(op) \ + template \ + constexpr inline integral_constant operator op( \ + integral_constant, integral_constant) noexcept \ + { \ + return {}; \ + } + +// NOLINTNEXTLINE +#define ROCM_INTEGRAL_CONSTANT_UNARY_OP(op) \ + template \ + constexpr inline integral_constant operator op( \ + integral_constant) noexcept \ + { \ + return {}; \ + } + +ROCM_INTEGRAL_CONSTANT_BINARY_OP(+) +ROCM_INTEGRAL_CONSTANT_BINARY_OP(-) +ROCM_INTEGRAL_CONSTANT_BINARY_OP(*) +ROCM_INTEGRAL_CONSTANT_BINARY_OP(/) +ROCM_INTEGRAL_CONSTANT_BINARY_OP(%) +// NOLINTBEGIN(hicpp-signed-bitwise) +ROCM_INTEGRAL_CONSTANT_BINARY_OP(>>) +ROCM_INTEGRAL_CONSTANT_BINARY_OP(<<) +// NOLINTEND(hicpp-signed-bitwise) +ROCM_INTEGRAL_CONSTANT_BINARY_OP(>) +ROCM_INTEGRAL_CONSTANT_BINARY_OP(<) +ROCM_INTEGRAL_CONSTANT_BINARY_OP(<=) +ROCM_INTEGRAL_CONSTANT_BINARY_OP(>=) +ROCM_INTEGRAL_CONSTANT_BINARY_OP(==) +ROCM_INTEGRAL_CONSTANT_BINARY_OP(!=) +// NOLINTBEGIN(hicpp-signed-bitwise) +ROCM_INTEGRAL_CONSTANT_BINARY_OP(&) +ROCM_INTEGRAL_CONSTANT_BINARY_OP(^) +ROCM_INTEGRAL_CONSTANT_BINARY_OP(|) +// NOLINTEND(hicpp-signed-bitwise) +ROCM_INTEGRAL_CONSTANT_BINARY_OP(and) +ROCM_INTEGRAL_CONSTANT_BINARY_OP(or) + +ROCM_INTEGRAL_CONSTANT_UNARY_OP(not) +// NOLINTNEXTLINE(hicpp-signed-bitwise) +ROCM_INTEGRAL_CONSTANT_UNARY_OP(~) +ROCM_INTEGRAL_CONSTANT_UNARY_OP(+) +ROCM_INTEGRAL_CONSTANT_UNARY_OP(-) + +template +using bool_constant = integral_constant; + +using true_type = bool_constant; +using false_type = bool_constant; + +} // namespace ROCM_INLINE_NS +} // namespace rocm +#endif // ROCM_GUARD_ROCM_INTEGRAL_CONSTANT_HPP diff --git a/src/targets/gpu/kernels/include/rocm/iterator.hpp b/src/targets/gpu/kernels/include/rocm/iterator.hpp new file mode 100644 index 00000000000..814fce17b8e --- /dev/null +++ b/src/targets/gpu/kernels/include/rocm/iterator.hpp @@ -0,0 +1,37 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2025-2026 Advanced Micro Devices, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#ifndef ROCM_GUARD_ROCM_ITERATOR_HPP +#define ROCM_GUARD_ROCM_ITERATOR_HPP + +#include +#include +#include + +namespace rocm { +inline namespace ROCM_INLINE_NS { + +} // namespace ROCM_INLINE_NS +} // namespace rocm +#endif // ROCM_GUARD_ROCM_ITERATOR_HPP diff --git a/src/targets/gpu/kernels/include/rocm/iterator/iterator_traits.hpp b/src/targets/gpu/kernels/include/rocm/iterator/iterator_traits.hpp new file mode 100644 index 00000000000..d949a20d22b --- /dev/null +++ b/src/targets/gpu/kernels/include/rocm/iterator/iterator_traits.hpp @@ -0,0 +1,77 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2025-2026 Advanced Micro Devices, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#ifndef ROCM_GUARD_ITERATOR_ITERATOR_TRAITS_HPP +#define ROCM_GUARD_ITERATOR_ITERATOR_TRAITS_HPP + +#include +#include +#include + +namespace rocm { +inline namespace ROCM_INLINE_NS { + +struct input_iterator_tag +{ +}; + +struct output_iterator_tag +{ +}; + +struct forward_iterator_tag : input_iterator_tag +{ +}; + +struct bidirectional_iterator_tag : forward_iterator_tag +{ +}; + +struct random_access_iterator_tag : bidirectional_iterator_tag +{ +}; + +template +struct iterator_traits +{ + using difference_type = typename Iterator::difference_type; + using value_type = typename Iterator::value_type; + using pointer = typename Iterator::pointer; + using reference = typename Iterator::reference; + using iterator_category = typename Iterator::iterator_category; +}; + +template +struct iterator_traits +{ + using difference_type = ptrdiff_t; + using value_type = remove_cv_t; + using pointer = T*; + using reference = T&; + using iterator_category = random_access_iterator_tag; +}; + +} // namespace ROCM_INLINE_NS +} // namespace rocm +#endif // ROCM_GUARD_ITERATOR_ITERATOR_TRAITS_HPP diff --git a/src/targets/gpu/kernels/include/rocm/iterator/reverse_iterator.hpp b/src/targets/gpu/kernels/include/rocm/iterator/reverse_iterator.hpp new file mode 100644 index 00000000000..1868a201d5f --- /dev/null +++ b/src/targets/gpu/kernels/include/rocm/iterator/reverse_iterator.hpp @@ -0,0 +1,191 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2025-2026 Advanced Micro Devices, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#ifndef ROCM_GUARD_ITERATOR_REVERSE_ITERATOR_HPP +#define ROCM_GUARD_ITERATOR_REVERSE_ITERATOR_HPP + +#include + +namespace rocm { +inline namespace ROCM_INLINE_NS { + +template +struct reverse_iterator +{ + using iterator_type = Iterator; + using difference_type = typename iterator_traits::difference_type; + using value_type = typename iterator_traits::value_type; + using pointer = typename iterator_traits::pointer; + using reference = typename iterator_traits::reference; + using iterator_category = typename iterator_traits::iterator_category; + + iterator_type current; + + constexpr reverse_iterator() : current() {} + + constexpr explicit reverse_iterator(iterator_type it) : current(it) {} + + template + constexpr reverse_iterator(const reverse_iterator& other) : current(other.base()) + { + } + + template + constexpr reverse_iterator& operator=(const reverse_iterator& other) + { + current = other.base(); + return *this; + } + + constexpr iterator_type base() const { return current; } + + constexpr reference operator*() const + { + iterator_type tmp = current; + --tmp; + return *tmp; + } + + constexpr pointer operator->() const + { + iterator_type tmp = current; + --tmp; + return tmp; + } + + constexpr reference operator[](difference_type n) const { return *(*this + n); } + + constexpr reverse_iterator& operator++() + { + --current; + return *this; + } + + constexpr reverse_iterator& operator--() + { + ++current; + return *this; + } + + constexpr reverse_iterator operator++(int) // NOLINT + { + reverse_iterator tmp = *this; + --current; + return tmp; + } + + constexpr reverse_iterator operator--(int) // NOLINT + { + reverse_iterator tmp = *this; + ++current; + return tmp; + } + + constexpr reverse_iterator& operator+=(difference_type n) + { + current -= n; + return *this; + } + + constexpr reverse_iterator& operator-=(difference_type n) + { + current += n; + return *this; + } + + friend constexpr reverse_iterator operator+(reverse_iterator it, difference_type n) + { + return it += n; + } + + friend constexpr reverse_iterator operator+(difference_type n, reverse_iterator it) + { + return it += n; + } + + friend constexpr reverse_iterator operator-(reverse_iterator it, difference_type n) + { + return it -= n; + } + + template + friend constexpr auto operator-(const reverse_iterator& lhs, + const reverse_iterator& rhs) + -> decltype(rhs.base() - lhs.base()) + { + return rhs.base() - lhs.base(); + } + + template + friend constexpr bool operator==(const reverse_iterator& lhs, + const reverse_iterator& rhs) + { + return lhs.base() == rhs.base(); + } + + template + friend constexpr bool operator!=(const reverse_iterator& lhs, + const reverse_iterator& rhs) + { + return lhs.base() != rhs.base(); + } + + template + friend constexpr bool operator<(const reverse_iterator& lhs, + const reverse_iterator& rhs) + { + return lhs.base() > rhs.base(); + } + + template + friend constexpr bool operator>(const reverse_iterator& lhs, + const reverse_iterator& rhs) + { + return lhs.base() < rhs.base(); + } + + template + friend constexpr bool operator<=(const reverse_iterator& lhs, + const reverse_iterator& rhs) + { + return lhs.base() >= rhs.base(); + } + + template + friend constexpr bool operator>=(const reverse_iterator& lhs, + const reverse_iterator& rhs) + { + return lhs.base() <= rhs.base(); + } +}; + +template +constexpr reverse_iterator make_reverse_iterator(Iterator it) +{ + return reverse_iterator(it); +} + +} // namespace ROCM_INLINE_NS +} // namespace rocm +#endif // ROCM_GUARD_ITERATOR_REVERSE_ITERATOR_HPP diff --git a/src/targets/gpu/kernels/include/rocm/limits.hpp b/src/targets/gpu/kernels/include/rocm/limits.hpp new file mode 100644 index 00000000000..118eaaaeb25 --- /dev/null +++ b/src/targets/gpu/kernels/include/rocm/limits.hpp @@ -0,0 +1,339 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2015-2026 Advanced Micro Devices, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#ifndef ROCM_GUARD_ROCM_LIMITS_HPP +#define ROCM_GUARD_ROCM_LIMITS_HPP + +#include + +namespace rocm { +inline namespace ROCM_INLINE_NS { + +enum float_round_style +{ + round_indeterminate = -1, + round_toward_zero = 0, + round_to_nearest = 1, + round_toward_infinity = 2, + round_toward_neg_infinity = 3 +}; + +namespace detail { + +constexpr unsigned long int_max(unsigned long n) +{ + // Note, left shift cannot be used to get the maximum value of int64_type or + // uint64_type because it is undefined behavior to left shift 64 bits for + // these types + if(n == 8) + return -1; + return (1ul << (n * 8)) - 1; +} + +template +struct numeric_limits_integer +{ + static constexpr const bool is_specialized = true; + + static constexpr const bool is_signed = T(-1) < T(0); + static constexpr const int digits = sizeof(T) * 8 - static_cast(is_signed); + static constexpr const int digits10 = digits * 3 / 10; + static constexpr const int max_digits10 = 0; + static constexpr T min() noexcept + { + if constexpr(is_signed) + return -max() - 1; + return 0; + } + static constexpr T max() noexcept + { + if constexpr(is_signed) + return int_max(sizeof(T)) / 2; + return int_max(sizeof(T)); + } + static constexpr T lowest() noexcept { return min(); } + + static constexpr const bool is_integer = true; + static constexpr const bool is_exact = true; + static constexpr const int radix = 2; + static constexpr T epsilon() noexcept { return T(0); } + static constexpr T round_error() noexcept { return T(0); } + + static constexpr const int min_exponent = 0; + static constexpr const int min_exponent10 = 0; + static constexpr const int max_exponent = 0; + static constexpr const int max_exponent10 = 0; + + static constexpr const bool has_infinity = false; + // NOLINTNEXTLINE(readability-identifier-naming) + static constexpr const bool has_quiet_NaN = false; + // NOLINTNEXTLINE(readability-identifier-naming) + static constexpr const bool has_signaling_NaN = false; + static constexpr T infinity() noexcept { return T(0); } + // NOLINTNEXTLINE(readability-identifier-naming) + static constexpr T quiet_NaN() noexcept { return T(0); } + // NOLINTNEXTLINE(readability-identifier-naming) + static constexpr T signaling_NaN() noexcept { return T(0); } + static constexpr T denorm_min() noexcept { return T(0); } + + static constexpr const bool is_iec559 = false; + static constexpr const bool is_bounded = true; + static constexpr const bool is_modulo = not is_signed; + + static constexpr const bool traps = false; + static constexpr const bool tinyness_before = false; + static constexpr const float_round_style round_style = round_toward_zero; +}; + +template +struct numeric_limits_fp_mixin : Base +{ + static constexpr const bool is_specialized = true; + + static constexpr const bool is_signed = true; + static constexpr const int max_digits10 = 2 + (Base::digits * 30103L) / 100000L; + static constexpr const bool is_integer = false; + static constexpr const bool is_exact = false; + static constexpr const int radix = __FLT_RADIX__; + static constexpr typename Base::type round_error() noexcept { return 0.5F; } + static constexpr typename Base::type lowest() noexcept { return -Base::max(); } + static constexpr const bool has_infinity = true; + // NOLINTNEXTLINE(readability-identifier-naming) + static constexpr const bool has_quiet_NaN = true; + // NOLINTNEXTLINE(readability-identifier-naming) + static constexpr const bool has_signaling_NaN = true; + static constexpr const bool is_iec559 = true; + static constexpr const bool is_bounded = true; + static constexpr const bool is_modulo = false; + + static constexpr const bool traps = false; + static constexpr const bool tinyness_before = false; + static constexpr const float_round_style round_style = round_to_nearest; +}; + +struct numeric_limits_float +{ + using type = float; + static constexpr const int digits = __FLT_MANT_DIG__; + static constexpr const int digits10 = __FLT_DIG__; + static constexpr type min() noexcept { return __FLT_MIN__; } + static constexpr type max() noexcept { return __FLT_MAX__; } + + static constexpr type epsilon() noexcept { return __FLT_EPSILON__; } + + static constexpr const int min_exponent = __FLT_MIN_EXP__; + static constexpr const int min_exponent10 = __FLT_MIN_10_EXP__; + static constexpr const int max_exponent = __FLT_MAX_EXP__; + static constexpr const int max_exponent10 = __FLT_MAX_10_EXP__; + + static constexpr type infinity() noexcept { return __builtin_huge_valf(); } + // NOLINTNEXTLINE(readability-identifier-naming) + static constexpr type quiet_NaN() noexcept { return __builtin_nanf(""); } + // NOLINTNEXTLINE(readability-identifier-naming) + static constexpr type signaling_NaN() noexcept { return __builtin_nansf(""); } + static constexpr type denorm_min() noexcept { return __FLT_DENORM_MIN__; } +}; + +struct numeric_limits_double +{ + using type = double; + + static constexpr const int digits = __DBL_MANT_DIG__; + static constexpr const int digits10 = __DBL_DIG__; + static constexpr type min() noexcept { return __DBL_MIN__; } + static constexpr type max() noexcept { return __DBL_MAX__; } + + static constexpr const int radix = __FLT_RADIX__; + static constexpr type epsilon() noexcept { return __DBL_EPSILON__; } + + static constexpr const int min_exponent = __DBL_MIN_EXP__; + static constexpr const int min_exponent10 = __DBL_MIN_10_EXP__; + static constexpr const int max_exponent = __DBL_MAX_EXP__; + static constexpr const int max_exponent10 = __DBL_MAX_10_EXP__; + + static constexpr type infinity() noexcept { return __builtin_huge_val(); } + // NOLINTNEXTLINE(readability-identifier-naming) + static constexpr type quiet_NaN() noexcept { return __builtin_nan(""); } + // NOLINTNEXTLINE(readability-identifier-naming) + static constexpr type signaling_NaN() noexcept { return __builtin_nans(""); } + static constexpr type denorm_min() noexcept { return __DBL_DENORM_MIN__; } +}; + +#ifdef __FLT16_MAX__ +struct numeric_limits_fp16 +{ + using type = _Float16; + + static constexpr const int digits = __FLT16_MANT_DIG__; + static constexpr const int digits10 = __FLT16_DIG__; + static constexpr type min() noexcept { return __FLT16_MIN__; } + static constexpr type max() noexcept { return __FLT16_MAX__; } + + static constexpr const int radix = __FLT_RADIX__; + static constexpr type epsilon() noexcept { return __FLT16_EPSILON__; } + + static constexpr const int min_exponent = __FLT16_MIN_EXP__; + static constexpr const int min_exponent10 = __FLT16_MIN_10_EXP__; + static constexpr const int max_exponent = __FLT16_MAX_EXP__; + static constexpr const int max_exponent10 = __FLT16_MAX_10_EXP__; + + static constexpr type infinity() noexcept { return __builtin_huge_valf16(); } + // NOLINTNEXTLINE(readability-identifier-naming) + static constexpr type quiet_NaN() noexcept { return __builtin_nanf16(""); } + // NOLINTNEXTLINE(readability-identifier-naming) + static constexpr type signaling_NaN() noexcept { return __builtin_nansf16(""); } + static constexpr type denorm_min() noexcept { return __FLT16_DENORM_MIN__; } +}; +#endif + +struct numeric_limits_bf16 +{ + using type = __bf16; + + static constexpr type from_bits(unsigned short bits) noexcept + { + return __builtin_bit_cast(type, bits); + } + + static constexpr const int digits = 8; + static constexpr const int digits10 = 2; + static constexpr type min() noexcept { return from_bits(0x0080); } + static constexpr type max() noexcept { return from_bits(0x7f7f); } + + static constexpr const int radix = __FLT_RADIX__; + static constexpr type epsilon() noexcept { return from_bits(0x3c00); } + + static constexpr const int min_exponent = -125; + static constexpr const int min_exponent10 = -37; + static constexpr const int max_exponent = 128; + static constexpr const int max_exponent10 = 38; + + static constexpr type infinity() noexcept { return from_bits(0x7f80); } + // NOLINTNEXTLINE(readability-identifier-naming) + static constexpr type quiet_NaN() noexcept { return from_bits(0x7fc0); } + // NOLINTNEXTLINE(readability-identifier-naming) + static constexpr type signaling_NaN() noexcept { return from_bits(0x7fa0); } + static constexpr type denorm_min() noexcept { return from_bits(0x0001); } +}; + +} // namespace detail + +template +struct numeric_limits +{ + static constexpr const bool is_specialized = false; + static constexpr T min() noexcept { return T(); } + static constexpr T max() noexcept { return T(); } + static constexpr T lowest() noexcept { return T(); } + + static constexpr const int digits = 0; + static constexpr const int digits10 = 0; + static constexpr const int max_digits10 = 0; + static constexpr const bool is_signed = false; + static constexpr const bool is_integer = false; + static constexpr const bool is_exact = false; + static constexpr const int radix = 0; + static constexpr T epsilon() noexcept { return T(); } + static constexpr T round_error() noexcept { return T(); } + + static constexpr const int min_exponent = 0; + static constexpr const int min_exponent10 = 0; + static constexpr const int max_exponent = 0; + static constexpr const int max_exponent10 = 0; + + static constexpr const bool has_infinity = false; + // NOLINTNEXTLINE(readability-identifier-naming) + static constexpr const bool has_quiet_NaN = false; + // NOLINTNEXTLINE(readability-identifier-naming) + static constexpr const bool has_signaling_NaN = false; + static constexpr T infinity() noexcept { return T(); } + // NOLINTNEXTLINE(readability-identifier-naming) + static constexpr T quiet_NaN() noexcept { return T(); } + // NOLINTNEXTLINE(readability-identifier-naming) + static constexpr T signaling_NaN() noexcept { return T(); } + static constexpr T denorm_min() noexcept { return T(); } + + static constexpr const bool is_iec559 = false; + static constexpr const bool is_bounded = false; + static constexpr const bool is_modulo = false; + + static constexpr const bool traps = false; + static constexpr const bool tinyness_before = false; + static constexpr const float_round_style round_style = round_toward_zero; +}; + +template +struct numeric_limits : numeric_limits +{ +}; + +template +struct numeric_limits : numeric_limits +{ +}; + +template +struct numeric_limits : numeric_limits +{ +}; + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define ROCM_DEFINE_NUMERIC_LIMITS_INT(T) \ + template <> \ + struct numeric_limits : detail::numeric_limits_integer \ + { \ + } + +ROCM_DEFINE_NUMERIC_LIMITS_INT(char); +ROCM_DEFINE_NUMERIC_LIMITS_INT(signed char); +ROCM_DEFINE_NUMERIC_LIMITS_INT(unsigned char); +ROCM_DEFINE_NUMERIC_LIMITS_INT(wchar_t); +ROCM_DEFINE_NUMERIC_LIMITS_INT(char16_t); +ROCM_DEFINE_NUMERIC_LIMITS_INT(char32_t); +ROCM_DEFINE_NUMERIC_LIMITS_INT(short); +ROCM_DEFINE_NUMERIC_LIMITS_INT(unsigned short); +ROCM_DEFINE_NUMERIC_LIMITS_INT(int); +ROCM_DEFINE_NUMERIC_LIMITS_INT(unsigned int); +ROCM_DEFINE_NUMERIC_LIMITS_INT(long); +ROCM_DEFINE_NUMERIC_LIMITS_INT(unsigned long); +ROCM_DEFINE_NUMERIC_LIMITS_INT(long long); +ROCM_DEFINE_NUMERIC_LIMITS_INT(unsigned long long); + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define ROCM_DEFINE_NUMERIC_LIMITS_FLOAT(T, base) \ + template <> \ + struct numeric_limits : detail::numeric_limits_fp_mixin \ + { \ + } + +ROCM_DEFINE_NUMERIC_LIMITS_FLOAT(float, numeric_limits_float); +ROCM_DEFINE_NUMERIC_LIMITS_FLOAT(double, numeric_limits_double); +#ifdef __FLT16_MAX__ +ROCM_DEFINE_NUMERIC_LIMITS_FLOAT(_Float16, numeric_limits_fp16); +#endif +ROCM_DEFINE_NUMERIC_LIMITS_FLOAT(__bf16, numeric_limits_bf16); + +} // namespace ROCM_INLINE_NS +} // namespace rocm +#endif // ROCM_GUARD_ROCM_LIMITS_HPP diff --git a/src/targets/gpu/kernels/include/rocm/stddef.hpp b/src/targets/gpu/kernels/include/rocm/stddef.hpp new file mode 100644 index 00000000000..cb16d056ee3 --- /dev/null +++ b/src/targets/gpu/kernels/include/rocm/stddef.hpp @@ -0,0 +1,40 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2025-2026 Advanced Micro Devices, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#ifndef ROCM_GUARD_ROCM_STDDEF_HPP +#define ROCM_GUARD_ROCM_STDDEF_HPP + +#include +#include + +namespace rocm { +inline namespace ROCM_INLINE_NS { + +using nullptr_t = decltype(nullptr); +using size_t = uint64_t; +using ptrdiff_t = int64_t; + +} // namespace ROCM_INLINE_NS +} // namespace rocm +#endif // ROCM_GUARD_ROCM_STDDEF_HPP diff --git a/src/targets/gpu/kernels/include/rocm/stdint.hpp b/src/targets/gpu/kernels/include/rocm/stdint.hpp new file mode 100644 index 00000000000..98b7f11e678 --- /dev/null +++ b/src/targets/gpu/kernels/include/rocm/stdint.hpp @@ -0,0 +1,65 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2015-2026 Advanced Micro Devices, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#ifndef ROCM_GUARD_ROCM_STDINT_HPP +#define ROCM_GUARD_ROCM_STDINT_HPP + +#include + +#ifndef __HIPCC_RTC__ +#include +#endif + +namespace rocm { +inline namespace ROCM_INLINE_NS { + +#ifdef __HIPCC_RTC__ +using int8_t = __hip_int8_t; +using uint8_t = __hip_uint8_t; +using int16_t = __hip_int16_t; +using uint16_t = __hip_uint16_t; +using int32_t = __hip_int32_t; +using uint32_t = __hip_uint32_t; +using int64_t = __hip_int64_t; +using uint64_t = __hip_uint64_t; +#else +using int8_t = std::int8_t; +using uint8_t = std::uint8_t; +using int16_t = std::int16_t; +using uint16_t = std::uint16_t; +using int32_t = std::int32_t; +using uint32_t = std::uint32_t; +using int64_t = std::int64_t; +using uint64_t = std::uint64_t; +#endif + +using intptr_t = int64_t; +using uintptr_t = uint64_t; +using intmax_t = int64_t; +using uintmax_t = uint64_t; +using intmax_t = int64_t; + +} // namespace ROCM_INLINE_NS +} // namespace rocm +#endif // ROCM_GUARD_ROCM_STDINT_HPP diff --git a/src/targets/gpu/kernels/include/rocm/type_traits.hpp b/src/targets/gpu/kernels/include/rocm/type_traits.hpp new file mode 100644 index 00000000000..1dd669fe396 --- /dev/null +++ b/src/targets/gpu/kernels/include/rocm/type_traits.hpp @@ -0,0 +1,317 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2015-2026 Advanced Micro Devices, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#ifndef ROCM_GUARD_ROCM_TYPE_TRAITS_HPP +#define ROCM_GUARD_ROCM_TYPE_TRAITS_HPP + +#include +#include +#include +#include + +namespace rocm { +inline namespace ROCM_INLINE_NS { + +template +struct type_identity +{ + using type = T; +}; + +template +using type_identity_t = typename type_identity::type; + +template +struct enable_if +{ +}; + +template +struct enable_if +{ + using type = T; +}; + +template +using enable_if_t = typename enable_if::type; + +template +struct conditional +{ + using type = T; +}; + +template +struct conditional +{ + using type = F; +}; + +template +using conditional_t = typename conditional::type; + +template +struct add_cv +{ + using type = const volatile T; +}; +template +using add_cv_t = typename add_cv::type; + +template +struct add_const +{ + using type = const T; +}; +template +using add_const_t = typename add_const::type; + +template +struct add_volatile +{ + using type = volatile T; +}; +template +using add_volatile_t = typename add_volatile::type; + +template +struct remove_cv +{ + using type = T; +}; + +template +struct remove_cv : remove_cv +{ +}; + +template +struct remove_cv : remove_cv +{ +}; + +template +struct remove_cv : remove_cv +{ +}; + +template +using remove_cv_t = typename remove_cv::type; + +template +struct remove_const +{ + using type = T; +}; +template +struct remove_const +{ + using type = T; +}; +template +using remove_const_t = typename remove_const::type; + +template +struct remove_reference +{ + using type = T; +}; +template +struct remove_reference +{ + using type = T; +}; +template +struct remove_reference +{ + using type = T; +}; + +template +using remove_reference_t = typename remove_reference::type; + +template +struct remove_cvref : remove_cv> +{ +}; +template +using remove_cvref_t = typename remove_cvref::type; + +template +struct add_pointer : type_identity*> +{ +}; + +template +using add_pointer_t = typename add_pointer::type; + +template +struct remove_pointer +{ + using type = T; +}; +template +struct remove_pointer +{ + using type = T; +}; +template +struct remove_pointer +{ + using type = T; +}; +template +struct remove_pointer +{ + using type = T; +}; +template +struct remove_pointer +{ + using type = T; +}; + +template +using remove_pointer_t = typename remove_pointer::type; + +template +struct common_type; + +template +struct common_type +{ + using type = typename common_type::type; +}; + +template +struct common_type +{ + using type = remove_cv_t() : declval())>>; +}; + +template +struct common_type +{ + using type = typename common_type::type, Us...>::type; +}; + +template +using common_type_t = typename common_type::type; + +template +using void_t = void; + +// NOLINTNEXTLINE +#define ROCM_BUILTIN_TYPE_TRAIT1(name) \ + template \ + struct name : bool_constant<__##name(T)> \ + { \ + }; \ + template \ + inline constexpr bool name##_v = __##name(T) + +// NOLINTNEXTLINE +#define ROCM_BUILTIN_TYPE_TRAIT2(name) \ + template \ + struct name : bool_constant<__##name(T, U)> \ + { \ + }; \ + template \ + inline constexpr bool name##_v = __##name(T, U) + +// NOLINTNEXTLINE +#define ROCM_BUILTIN_TYPE_TRAITN(name) \ + template \ + struct name : bool_constant<__##name(Ts...)> \ + { \ + }; \ + template \ + inline constexpr bool name##_v = __##name(Ts...) + +// ROCM_BUILTIN_TYPE_TRAIT1(is_destructible); +// ROCM_BUILTIN_TYPE_TRAIT1(is_nothrow_destructible); +// ROCM_BUILTIN_TYPE_TRAIT1(is_scalar); +// ROCM_BUILTIN_TYPE_TRAIT1(is_signed); +// ROCM_BUILTIN_TYPE_TRAIT1(is_void); +ROCM_BUILTIN_TYPE_TRAIT1(is_abstract); +ROCM_BUILTIN_TYPE_TRAIT1(is_aggregate); +ROCM_BUILTIN_TYPE_TRAIT1(is_arithmetic); +ROCM_BUILTIN_TYPE_TRAIT1(is_array); +ROCM_BUILTIN_TYPE_TRAIT1(is_class); +ROCM_BUILTIN_TYPE_TRAIT1(is_compound); +ROCM_BUILTIN_TYPE_TRAIT1(is_const); +ROCM_BUILTIN_TYPE_TRAIT1(is_empty); +ROCM_BUILTIN_TYPE_TRAIT1(is_enum); +ROCM_BUILTIN_TYPE_TRAIT1(is_final); +ROCM_BUILTIN_TYPE_TRAIT1(is_floating_point); +ROCM_BUILTIN_TYPE_TRAIT1(is_function); +ROCM_BUILTIN_TYPE_TRAIT1(is_fundamental); +ROCM_BUILTIN_TYPE_TRAIT1(is_integral); +ROCM_BUILTIN_TYPE_TRAIT1(is_literal_type); +ROCM_BUILTIN_TYPE_TRAIT1(is_lvalue_reference); +ROCM_BUILTIN_TYPE_TRAIT1(is_member_function_pointer); +ROCM_BUILTIN_TYPE_TRAIT1(is_member_object_pointer); +ROCM_BUILTIN_TYPE_TRAIT1(is_member_pointer); +ROCM_BUILTIN_TYPE_TRAIT1(is_object); +ROCM_BUILTIN_TYPE_TRAIT1(is_pod); +ROCM_BUILTIN_TYPE_TRAIT1(is_pointer); +ROCM_BUILTIN_TYPE_TRAIT1(is_polymorphic); +ROCM_BUILTIN_TYPE_TRAIT1(is_reference); +ROCM_BUILTIN_TYPE_TRAIT1(is_rvalue_reference); +ROCM_BUILTIN_TYPE_TRAIT1(is_standard_layout); +ROCM_BUILTIN_TYPE_TRAIT1(is_trivial); +ROCM_BUILTIN_TYPE_TRAIT1(is_trivially_copyable); +ROCM_BUILTIN_TYPE_TRAIT1(is_trivially_destructible); +ROCM_BUILTIN_TYPE_TRAIT1(is_union); +ROCM_BUILTIN_TYPE_TRAIT1(is_unsigned); +ROCM_BUILTIN_TYPE_TRAIT1(is_volatile); +ROCM_BUILTIN_TYPE_TRAIT2(is_assignable); +ROCM_BUILTIN_TYPE_TRAIT2(is_base_of); +ROCM_BUILTIN_TYPE_TRAIT2(is_convertible); +ROCM_BUILTIN_TYPE_TRAIT2(is_nothrow_assignable); +ROCM_BUILTIN_TYPE_TRAIT2(is_same); +ROCM_BUILTIN_TYPE_TRAIT2(is_trivially_assignable); +ROCM_BUILTIN_TYPE_TRAITN(is_constructible); +ROCM_BUILTIN_TYPE_TRAITN(is_nothrow_constructible); +ROCM_BUILTIN_TYPE_TRAITN(is_trivially_constructible); + +template +struct is_void : is_same> +{ +}; +template +inline constexpr bool is_void_v = is_void{}; + +template +struct is_null_pointer : is_same> +{ +}; +template +inline constexpr bool is_null_pointer_v = is_null_pointer{}; + +#define ROCM_REQUIRES(...) class = enable_if_t<__VA_ARGS__> + +} // namespace ROCM_INLINE_NS +} // namespace rocm +#endif // ROCM_GUARD_ROCM_TYPE_TRAITS_HPP diff --git a/src/targets/gpu/kernels/include/rocm/utility.hpp b/src/targets/gpu/kernels/include/rocm/utility.hpp new file mode 100644 index 00000000000..eae47080cfb --- /dev/null +++ b/src/targets/gpu/kernels/include/rocm/utility.hpp @@ -0,0 +1,40 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2025-2026 Advanced Micro Devices, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#ifndef ROCM_GUARD_ROCM_UTILITY_HPP +#define ROCM_GUARD_ROCM_UTILITY_HPP + +#include +#include +#include +#include +#include +#include + +namespace rocm { +inline namespace ROCM_INLINE_NS { + +} // namespace ROCM_INLINE_NS +} // namespace rocm +#endif // ROCM_GUARD_ROCM_UTILITY_HPP diff --git a/src/targets/gpu/kernels/include/rocm/utility/declval.hpp b/src/targets/gpu/kernels/include/rocm/utility/declval.hpp new file mode 100644 index 00000000000..b340c8001cc --- /dev/null +++ b/src/targets/gpu/kernels/include/rocm/utility/declval.hpp @@ -0,0 +1,44 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2015-2026 Advanced Micro Devices, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#ifndef ROCM_GUARD_ROCM_DECLVAL_HPP +#define ROCM_GUARD_ROCM_DECLVAL_HPP + +#include + +namespace rocm { +inline namespace ROCM_INLINE_NS { + +template +U private_declval(int); + +template +T private_declval(long); + +template +auto declval() noexcept -> decltype(private_declval(0)); + +} // namespace ROCM_INLINE_NS +} // namespace rocm +#endif // ROCM_GUARD_ROCM_DECLVAL_HPP diff --git a/src/targets/gpu/kernels/include/rocm/utility/forward.hpp b/src/targets/gpu/kernels/include/rocm/utility/forward.hpp new file mode 100644 index 00000000000..f4add3b1980 --- /dev/null +++ b/src/targets/gpu/kernels/include/rocm/utility/forward.hpp @@ -0,0 +1,51 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2025-2026 Advanced Micro Devices, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#ifndef ROCM_GUARD_UTILITY_FORWARD_HPP +#define ROCM_GUARD_UTILITY_FORWARD_HPP + +#include +#include + +namespace rocm { +inline namespace ROCM_INLINE_NS { + +template +constexpr T&& forward(remove_reference_t& x) noexcept +{ + return static_cast(x); +} + +template +constexpr T&& +// NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved) +forward(remove_reference_t&& x) noexcept +{ + static_assert(not is_lvalue_reference{}, "can not forward an rvalue as an lvalue"); + return static_cast(x); +} + +} // namespace ROCM_INLINE_NS +} // namespace rocm +#endif // ROCM_GUARD_UTILITY_FORWARD_HPP diff --git a/src/targets/gpu/kernels/include/rocm/utility/integer_sequence.hpp b/src/targets/gpu/kernels/include/rocm/utility/integer_sequence.hpp new file mode 100644 index 00000000000..4a569617f45 --- /dev/null +++ b/src/targets/gpu/kernels/include/rocm/utility/integer_sequence.hpp @@ -0,0 +1,56 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2025-2026 Advanced Micro Devices, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#ifndef ROCM_GUARD_UTILITY_INTEGER_SEQUENCE_HPP +#define ROCM_GUARD_UTILITY_INTEGER_SEQUENCE_HPP + +#include +#include + +namespace rocm { +inline namespace ROCM_INLINE_NS { + +template +struct integer_sequence +{ + using value_type = T; + + static constexpr size_t size() noexcept { return sizeof...(Ints); } +}; + +template +using index_sequence = integer_sequence; + +template +using make_integer_sequence = __make_integer_seq; + +template +using make_index_sequence = make_integer_sequence; + +template +using index_sequence_for = make_index_sequence; + +} // namespace ROCM_INLINE_NS +} // namespace rocm +#endif // ROCM_GUARD_UTILITY_INTEGER_SEQUENCE_HPP diff --git a/src/targets/gpu/kernels/include/rocm/utility/move.hpp b/src/targets/gpu/kernels/include/rocm/utility/move.hpp new file mode 100644 index 00000000000..4dbbc3d4a97 --- /dev/null +++ b/src/targets/gpu/kernels/include/rocm/utility/move.hpp @@ -0,0 +1,42 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2025-2026 Advanced Micro Devices, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#ifndef ROCM_GUARD_UTILITY_MOVE_HPP +#define ROCM_GUARD_UTILITY_MOVE_HPP + +#include +#include + +namespace rocm { +inline namespace ROCM_INLINE_NS { + +template +constexpr remove_reference_t&& move(T&& x) noexcept +{ + return static_cast&&>(x); +} + +} // namespace ROCM_INLINE_NS +} // namespace rocm +#endif // ROCM_GUARD_UTILITY_MOVE_HPP diff --git a/src/targets/gpu/kernels/include/rocm/utility/swap.hpp b/src/targets/gpu/kernels/include/rocm/utility/swap.hpp new file mode 100644 index 00000000000..00e96c696a0 --- /dev/null +++ b/src/targets/gpu/kernels/include/rocm/utility/swap.hpp @@ -0,0 +1,45 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2025-2026 Advanced Micro Devices, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#ifndef ROCM_GUARD_UTILITY_SWAP_HPP +#define ROCM_GUARD_UTILITY_SWAP_HPP + +#include + +namespace rocm { +inline namespace ROCM_INLINE_NS { + +template +constexpr void swap(T& a, T& b) noexcept +{ + // The cast to an rvalue reference is a move, not a redundant cast. + // cppcheck-suppress migraphx-RedundantCast + T tmp = static_cast(a); + a = static_cast(b); + b = static_cast(tmp); +} + +} // namespace ROCM_INLINE_NS +} // namespace rocm +#endif // ROCM_GUARD_UTILITY_SWAP_HPP diff --git a/test/gpu/kernels/CMakeLists.txt b/test/gpu/kernels/CMakeLists.txt index 98b9e8ff87f..16e3a9dd145 100644 --- a/test/gpu/kernels/CMakeLists.txt +++ b/test/gpu/kernels/CMakeLists.txt @@ -1,7 +1,7 @@ ##################################################################################### # The MIT License (MIT) # -# Copyright (c) 2015-2025 Advanced Micro Devices, Inc. All rights reserved. +# Copyright (c) 2015-2026 Advanced Micro Devices, Inc. All rights reserved. # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal @@ -22,7 +22,7 @@ # THE SOFTWARE. ##################################################################################### -file(GLOB KERNELS_TESTS CONFIGURE_DEPENDS *.cpp) +file(GLOB_RECURSE KERNELS_TESTS LIST_DIRECTORIES false CONFIGURE_DEPENDS *.cpp) list(REMOVE_ITEM KERNELS_TESTS ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) message("KERNELS_TESTS: ${KERNELS_TESTS}") diff --git a/test/gpu/kernels/main.cpp b/test/gpu/kernels/main.cpp index 0c6970305cf..b654ef831ed 100644 --- a/test/gpu/kernels/main.cpp +++ b/test/gpu/kernels/main.cpp @@ -1,7 +1,7 @@ /* * The MIT License (MIT) * - * Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved. + * Copyright (c) 2025-2026 Advanced Micro Devices, Inc. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -39,14 +40,14 @@ std::vector parse_cases(const std::string_view& content) { - std::regex case_re(R"(TEST_CASE\s*\(\s*([A-Za-z_][A-Za-z0-9_]*)\s*\))"); + std::regex case_re(R"((TEST_CASE_REGISTER|TEST_CASE)\s*\(\s*([A-Za-z_][A-Za-z0-9_<>:]*)\s*\))"); std::match_results m; std::vector test_names; auto it = content.cbegin(); while(std::regex_search(it, content.cend(), m, case_re)) { - test_names.push_back(m[1].str()); + test_names.push_back(m[2].str()); it = m.suffix().first; } return test_names; @@ -60,8 +61,15 @@ struct test_suite : std::enable_shared_from_this migraphx::gpu::hip_compile_options options = {}; migraphx::gpu::kernel k; + static std::string parse_suite_name(const std::string_view& src) + { + auto result = std::string{src.substr(0, src.size() - 4)}; + migraphx::replace_string_inplace(result, "/", "."); + return result; + } + test_suite(const std::string_view& src_name, const std::string_view& src_content) - : name(src_name.substr(0, src_name.size() - 4)), content(src_content) + : name(parse_suite_name(src_name)), content(src_content) { auto cases = parse_cases(src_content); for(std::size_t i = 0; i < cases.size(); ++i) @@ -73,6 +81,7 @@ struct test_suite : std::enable_shared_from_this options.global = 1; options.local = ctx.get_current_device().get_wavefront_size(); options.kernel_name = "gpu_test_kernel"; + options.src_file = src_name; } std::string generate_source() const diff --git a/test/gpu/kernels/rocm/.clang-tidy b/test/gpu/kernels/rocm/.clang-tidy new file mode 100644 index 00000000000..843a27cb54f --- /dev/null +++ b/test/gpu/kernels/rocm/.clang-tidy @@ -0,0 +1,6 @@ +InheritParentConfig: True +CheckOptions: + - key: readability-identifier-naming.MacroDefinitionPrefix + value: ROCM_ + - key: readability-identifier-naming.ConstexprMethodIgnoredRegexp + value: 'quiet_NaN|signaling_NaN' diff --git a/test/gpu/kernels/rocm/algorithm.cpp b/test/gpu/kernels/rocm/algorithm.cpp new file mode 100644 index 00000000000..5620bd038b1 --- /dev/null +++ b/test/gpu/kernels/rocm/algorithm.cpp @@ -0,0 +1,1326 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2025-2026 Advanced Micro Devices, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#include +#include +#include +#include + +struct empty_range +{ + constexpr int* begin() { return nullptr; } + + constexpr int* end() { return nullptr; } +}; + +TEST_CASE(iter_swap_basic) +{ + rocm::array arr = {1, 2, 3}; + rocm::iter_swap(arr.begin(), arr.begin() + 2); + rocm::array expected = {3, 2, 1}; + EXPECT(arr == expected); +} +TEST_CASE(iter_swap_same_iterator) +{ + rocm::array arr = {1, 2, 3}; + rocm::array original = arr; + rocm::iter_swap(arr.begin(), arr.begin()); + EXPECT(arr == original); +} +TEST_CASE(iter_swap_adjacent) +{ + rocm::array arr = {10, 20, 30, 40}; + rocm::iter_swap(arr.begin() + 1, arr.begin() + 2); + rocm::array expected = {10, 30, 20, 40}; + EXPECT(arr == expected); +} + +TEST_CASE(accumulate_basic) +{ + rocm::array arr = {1, 2, 3, 4}; + auto sum = rocm::accumulate(arr.begin(), arr.end(), 0, [](int a, int b) { return a + b; }); + EXPECT(sum == 10); +} +TEST_CASE(accumulate_empty_range) +{ + empty_range arr = {}; + auto sum = rocm::accumulate(arr.begin(), arr.begin(), 42, [](int a, int b) { return a + b; }); + EXPECT(sum == 42); +} +TEST_CASE(accumulate_multiply) +{ + rocm::array arr = {2, 3, 4}; + auto product = rocm::accumulate(arr.begin(), arr.end(), 1, [](int a, int b) { return a * b; }); + EXPECT(product == 24); +} +TEST_CASE(accumulate_single_element) +{ + rocm::array arr = {7}; + auto sum = rocm::accumulate(arr.begin(), arr.end(), 5, [](int a, int b) { return a + b; }); + EXPECT(sum == 12); +} + +TEST_CASE(copy_basic) +{ + rocm::array src = {1, 2, 3, 4}; + rocm::array dst = {0, 0, 0, 0}; + rocm::copy(src.begin(), src.end(), dst.begin()); + EXPECT(src == dst); +} +TEST_CASE(copy_empty_range) +{ + rocm::array src = {1, 2, 3}; + rocm::array dst = {0, 0, 0}; + auto* result = rocm::copy(src.begin(), src.begin(), dst.begin()); + EXPECT(result == dst.begin()); + rocm::array expected = {0, 0, 0}; + EXPECT(dst == expected); +} +TEST_CASE(copy_partial) +{ + rocm::array src = {10, 20, 30, 40, 50}; + rocm::array dst = {0, 0, 0}; + rocm::copy(src.begin() + 1, src.begin() + 4, dst.begin()); + rocm::array expected = {20, 30, 40}; + EXPECT(dst == expected); +} +TEST_CASE(copy_if_basic) +{ + rocm::array src = {1, 2, 3, 4, 5, 6}; + rocm::array dst = {0, 0, 0, 0, 0, 0}; + auto* end_it = + rocm::copy_if(src.begin(), src.end(), dst.begin(), [](int x) { return x % 2 == 0; }); + EXPECT(dst[0] == 2); + EXPECT(dst[1] == 4); + EXPECT(dst[2] == 6); + EXPECT(end_it == dst.begin() + 3); +} +TEST_CASE(copy_if_none_match) +{ + rocm::array src = {1, 3, 5}; + rocm::array dst = {0, 0, 0}; + auto* end_it = + rocm::copy_if(src.begin(), src.end(), dst.begin(), [](int x) { return x % 2 == 0; }); + EXPECT(end_it == dst.begin()); + rocm::array expected = {0, 0, 0}; + EXPECT(dst == expected); +} +TEST_CASE(copy_if_all_match) +{ + rocm::array src = {2, 4, 6}; + rocm::array dst = {0, 0, 0}; + auto* end_it = + rocm::copy_if(src.begin(), src.end(), dst.begin(), [](int x) { return x % 2 == 0; }); + EXPECT(end_it == dst.end()); + EXPECT(src == dst); +} + +TEST_CASE(is_sorted_until_sorted) +{ + rocm::array arr = {1, 2, 3, 4}; + auto* result = rocm::is_sorted_until(arr.begin(), arr.end(), rocm::less<>{}); + EXPECT(result == arr.end()); +} +TEST_CASE(is_sorted_until_unsorted) +{ + rocm::array arr = {1, 2, 4, 3, 5}; + auto* result = rocm::is_sorted_until(arr.begin(), arr.end(), rocm::less<>{}); + EXPECT(result == arr.begin() + 3); +} +TEST_CASE(is_sorted_until_empty) +{ + empty_range arr = {}; + auto* result = rocm::is_sorted_until(arr.begin(), arr.end(), rocm::less<>{}); + EXPECT(result == arr.end()); +} +TEST_CASE(is_sorted_until_single) +{ + rocm::array arr = {42}; + auto* result = rocm::is_sorted_until(arr.begin(), arr.end(), rocm::less<>{}); + EXPECT(result == arr.end()); +} +TEST_CASE(is_sorted_until_descending) +{ + rocm::array arr = {4, 3, 2, 1}; + auto* result = rocm::is_sorted_until(arr.begin(), arr.end(), rocm::greater<>{}); + EXPECT(result == arr.end()); +} +TEST_CASE(is_sorted_true) +{ + rocm::array arr = {1, 2, 3, 4}; + EXPECT(rocm::is_sorted(arr.begin(), arr.end(), rocm::less<>{})); +} +TEST_CASE(is_sorted_false) +{ + rocm::array arr = {1, 3, 2, 4}; + EXPECT(not rocm::is_sorted(arr.begin(), arr.end(), rocm::less<>{})); +} +TEST_CASE(is_sorted_empty) +{ + empty_range arr = {}; + EXPECT(rocm::is_sorted(arr.begin(), arr.end(), rocm::less<>{})); +} +TEST_CASE(is_sorted_duplicates) +{ + rocm::array arr = {1, 2, 2, 3}; + EXPECT(rocm::is_sorted(arr.begin(), arr.end(), rocm::less<>{})); +} + +TEST_CASE(for_each_basic) +{ + rocm::array arr = {1, 2, 3}; + int sum = 0; + rocm::for_each(arr.begin(), arr.end(), [&sum](int x) { sum += x; }); + EXPECT(sum == 6); +} +TEST_CASE(for_each_modify) +{ + rocm::array arr = {1, 2, 3}; + rocm::for_each(arr.begin(), arr.end(), [](int& x) { x *= 2; }); + rocm::array expected = {2, 4, 6}; + EXPECT(arr == expected); +} +TEST_CASE(for_each_empty) +{ + empty_range arr = {}; + int count = 0; + rocm::for_each(arr.begin(), arr.end(), [&count](int) { count++; }); + EXPECT(count == 0); +} + +TEST_CASE(find_if_found) +{ + rocm::array arr = {1, 3, 5, 7, 9}; + auto* result = rocm::find_if(arr.begin(), arr.end(), [](int x) { return x > 5; }); + EXPECT(result == arr.begin() + 3); +} +TEST_CASE(find_if_not_found) +{ + rocm::array arr = {1, 3, 5, 7}; + auto* result = rocm::find_if(arr.begin(), arr.end(), [](int x) { return x > 10; }); + EXPECT(result == arr.end()); +} +TEST_CASE(find_if_first_element) +{ + rocm::array arr = {10, 3, 5, 7}; + auto* result = rocm::find_if(arr.begin(), arr.end(), [](int x) { return x > 5; }); + EXPECT(result == arr.begin()); +} +TEST_CASE(find_if_empty) +{ + empty_range arr = {}; + auto* result = rocm::find_if(arr.begin(), arr.end(), [](int x) { return x > 0; }); + EXPECT(result == arr.end()); +} +TEST_CASE(find_basic) +{ + rocm::array arr = {10, 20, 30, 40}; + auto* result = rocm::find(arr.begin(), arr.end(), 30); + EXPECT(result == arr.begin() + 2); +} +TEST_CASE(find_not_found) +{ + rocm::array arr = {10, 20, 30, 40}; + auto* result = rocm::find(arr.begin(), arr.end(), 50); + EXPECT(result == arr.end()); +} +TEST_CASE(find_first_element) +{ + rocm::array arr = {10, 20, 30, 40}; + auto* result = rocm::find(arr.begin(), arr.end(), 10); + EXPECT(result == arr.begin()); +} +TEST_CASE(find_duplicates) +{ + rocm::array arr = {10, 20, 30, 20, 40}; + auto* result = rocm::find(arr.begin(), arr.end(), 20); + EXPECT(result == arr.begin() + 1); +} + +TEST_CASE(any_of_true) +{ + rocm::array arr = {1, 3, 5, 7}; + EXPECT(rocm::any_of(arr.begin(), arr.end(), [](int x) { return x > 5; })); +} +TEST_CASE(any_of_false) +{ + rocm::array arr = {1, 3, 5, 7}; + EXPECT(not rocm::any_of(arr.begin(), arr.end(), [](int x) { return x > 10; })); +} +TEST_CASE(any_of_empty) +{ + empty_range arr = {}; + EXPECT(not rocm::any_of(arr.begin(), arr.end(), [](int x) { return x > 0; })); +} +TEST_CASE(any_of_first_element) +{ + rocm::array arr = {10, 1, 2, 3}; + EXPECT(rocm::any_of(arr.begin(), arr.end(), [](int x) { return x > 5; })); +} +TEST_CASE(none_of_true) +{ + rocm::array arr = {1, 3, 5, 7}; + EXPECT(rocm::none_of(arr.begin(), arr.end(), [](int x) { return x > 10; })); +} +TEST_CASE(none_of_false) +{ + rocm::array arr = {1, 3, 5, 7}; + EXPECT(not rocm::none_of(arr.begin(), arr.end(), [](int x) { return x > 5; })); +} +TEST_CASE(none_of_empty) +{ + empty_range arr = {}; + EXPECT(rocm::none_of(arr.begin(), arr.end(), [](int x) { return x > 0; })); +} +TEST_CASE(all_of_true) +{ + rocm::array arr = {2, 4, 6, 8}; + EXPECT(rocm::all_of(arr.begin(), arr.end(), [](int x) { return x % 2 == 0; })); +} +TEST_CASE(all_of_false) +{ + rocm::array arr = {2, 4, 5, 8}; + EXPECT(not rocm::all_of(arr.begin(), arr.end(), [](int x) { return x % 2 == 0; })); +} +TEST_CASE(all_of_empty) +{ + empty_range arr = {}; + EXPECT(rocm::all_of(arr.begin(), arr.end(), [](int x) { return x > 0; })); +} +TEST_CASE(all_of_single_true) +{ + rocm::array arr = {4}; + EXPECT(rocm::all_of(arr.begin(), arr.end(), [](int x) { return x % 2 == 0; })); +} +TEST_CASE(all_of_single_false) +{ + rocm::array arr = {5}; + EXPECT(not rocm::all_of(arr.begin(), arr.end(), [](int x) { return x % 2 == 0; })); +} + +TEST_CASE(search_found) +{ + rocm::array haystack = {1, 2, 3, 4, 3, 4}; + rocm::array needle = {3, 4}; + auto* result = rocm::search(haystack.begin(), haystack.end(), needle.begin(), needle.end()); + EXPECT(result == haystack.begin() + 2); +} +TEST_CASE(search_not_found) +{ + rocm::array haystack = {1, 2, 3, 4, 5}; + rocm::array needle = {6, 7}; + auto* result = rocm::search(haystack.begin(), haystack.end(), needle.begin(), needle.end()); + EXPECT(result == haystack.end()); +} +TEST_CASE(search_empty_needle) +{ + rocm::array haystack = {1, 2, 3}; + empty_range needle = {}; + auto* result = rocm::search(haystack.begin(), haystack.end(), needle.begin(), needle.end()); + EXPECT(result == haystack.begin()); +} +TEST_CASE(search_empty_haystack) +{ + empty_range haystack = {}; + rocm::array needle = {1}; + auto* result = rocm::search(haystack.begin(), haystack.end(), needle.begin(), needle.end()); + EXPECT(result == haystack.end()); +} +TEST_CASE(search_exact_match) +{ + rocm::array haystack = {1, 2, 3}; + rocm::array needle = {1, 2, 3}; + auto* result = rocm::search(haystack.begin(), haystack.end(), needle.begin(), needle.end()); + EXPECT(result == haystack.begin()); +} +TEST_CASE(search_partial_match) +{ + rocm::array haystack = {1, 2, 1, 2, 3}; + rocm::array needle = {1, 2, 3}; + auto* result = rocm::search(haystack.begin(), haystack.end(), needle.begin(), needle.end()); + EXPECT(result == haystack.begin() + 2); +} +// Additional search tests (extensive) +TEST_CASE(search_overlapping_pattern) +{ + rocm::array haystack = {1, 2, 1, 2, 1, 2, 3, 4}; + rocm::array needle = {1, 2, 3}; + auto* result = rocm::search(haystack.begin(), haystack.end(), needle.begin(), needle.end()); + EXPECT(result == haystack.begin() + 4); +} +TEST_CASE(search_pattern_at_end) +{ + rocm::array haystack = {1, 2, 3, 4, 5, 6}; + rocm::array needle = {5, 6}; + auto* result = rocm::search(haystack.begin(), haystack.end(), needle.begin(), needle.end()); + EXPECT(result == haystack.begin() + 4); +} +TEST_CASE(search_pattern_at_beginning) +{ + rocm::array haystack = {1, 2, 3, 4, 5, 6}; + rocm::array needle = {1, 2}; + auto* result = rocm::search(haystack.begin(), haystack.end(), needle.begin(), needle.end()); + EXPECT(result == haystack.begin()); +} +TEST_CASE(search_single_element_pattern) +{ + rocm::array haystack = {1, 3, 5, 7, 9}; + rocm::array needle = {5}; + auto* result = rocm::search(haystack.begin(), haystack.end(), needle.begin(), needle.end()); + EXPECT(result == haystack.begin() + 2); +} +TEST_CASE(search_single_element_pattern_not_found) +{ + rocm::array haystack = {1, 3, 5, 7, 9}; + rocm::array needle = {4}; + auto* result = rocm::search(haystack.begin(), haystack.end(), needle.begin(), needle.end()); + EXPECT(result == haystack.end()); +} +TEST_CASE(search_repeated_elements) +{ + rocm::array haystack = {2, 2, 2, 2, 1, 2, 2, 3}; + rocm::array needle = {2, 2, 3}; + auto* result = rocm::search(haystack.begin(), haystack.end(), needle.begin(), needle.end()); + EXPECT(result == haystack.begin() + 5); +} +TEST_CASE(search_partial_match_backtrack) +{ + rocm::array haystack = {1, 2, 3, 1, 2, 4, 1, 2, 3, 4}; + rocm::array needle = {1, 2, 3, 4}; + auto* result = rocm::search(haystack.begin(), haystack.end(), needle.begin(), needle.end()); + EXPECT(result == haystack.begin() + 6); +} +TEST_CASE(search_multiple_false_starts) +{ + rocm::array haystack = {1, 2, 1, 2, 1, 2, 1, 2, 3, 4, 5, 6}; + rocm::array needle = {1, 2, 3, 4}; + auto* result = rocm::search(haystack.begin(), haystack.end(), needle.begin(), needle.end()); + EXPECT(result == haystack.begin() + 6); +} +TEST_CASE(search_needle_longer_than_haystack) +{ + rocm::array haystack = {1, 2, 3}; + rocm::array needle = {1, 2, 3, 4, 5}; + auto* result = rocm::search(haystack.begin(), haystack.end(), needle.begin(), needle.end()); + EXPECT(result == haystack.end()); +} +TEST_CASE(search_identical_arrays) +{ + rocm::array haystack = {5, 10, 15, 20}; + rocm::array needle = {5, 10, 15, 20}; + auto* result = rocm::search(haystack.begin(), haystack.end(), needle.begin(), needle.end()); + EXPECT(result == haystack.begin()); +} +TEST_CASE(search_all_same_elements) +{ + rocm::array haystack = {3, 3, 3, 3, 3, 3}; + rocm::array needle = {3, 3, 3}; + auto* result = rocm::search(haystack.begin(), haystack.end(), needle.begin(), needle.end()); + EXPECT(result == haystack.begin()); +} +TEST_CASE(search_pattern_appears_multiple_times) +{ + rocm::array haystack = {1, 2, 3, 1, 2, 3, 1, 2, 3}; + rocm::array needle = {2, 3}; + auto* result = rocm::search(haystack.begin(), haystack.end(), needle.begin(), needle.end()); + EXPECT(result == haystack.begin() + 1); +} +TEST_CASE(search_partial_range) +{ + rocm::array haystack = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + rocm::array needle = {4, 5}; + auto* result = + rocm::search(haystack.begin() + 2, haystack.begin() + 7, needle.begin(), needle.end()); + EXPECT(result == haystack.begin() + 4); +} +TEST_CASE(search_stress_long_pattern) +{ + rocm::array haystack = {1, 1, 1, 1, 1, 2, 3, 4, 5, 6, 7, 8, 1, 1, 1}; + rocm::array needle = {2, 3, 4, 5, 6, 7}; + auto* result = rocm::search(haystack.begin(), haystack.end(), needle.begin(), needle.end()); + EXPECT(result == haystack.begin() + 5); +} +TEST_CASE(search_stress_worst_case_complexity) +{ + rocm::array haystack = {1, 1, 1, 1, 1, 1, 1, 2}; + rocm::array needle = {1, 1, 1, 1, 1, 1, 2}; + auto* result = rocm::search(haystack.begin(), haystack.end(), needle.begin(), needle.end()); + EXPECT(result == haystack.begin() + 1); +} + +TEST_CASE(inner_product_basic) +{ + rocm::array a = {1, 2, 3}; + rocm::array b = {4, 5, 6}; + auto result = rocm::inner_product(a.begin(), a.end(), b.begin(), 0); + EXPECT(result == 32); +} +TEST_CASE(inner_product_custom_ops) +{ + rocm::array a = {1, 2, 3}; + rocm::array b = {4, 5, 6}; + auto result = rocm::inner_product( + a.begin(), + a.end(), + b.begin(), + 1, + [](int x, int y) { return x * y; }, + [](int x, int y) { return x + y; }); + EXPECT(result == 315); +} +TEST_CASE(inner_product_empty) +{ + empty_range a = {}; + empty_range b = {}; + auto result = rocm::inner_product(a.begin(), a.end(), b.begin(), 42); + EXPECT(result == 42); +} +TEST_CASE(inner_product_single) +{ + rocm::array a = {3}; + rocm::array b = {7}; + auto result = rocm::inner_product(a.begin(), a.end(), b.begin(), 5); + EXPECT(result == 26); +} + +TEST_CASE(equal_true) +{ + rocm::array a = {1, 2, 3, 4}; + rocm::array b = {1, 2, 3, 4}; + EXPECT(rocm::equal(a.begin(), a.end(), b.begin(), [](int x, int y) { return x == y; })); +} +TEST_CASE(equal_false) +{ + rocm::array a = {1, 2, 3, 4}; + rocm::array b = {1, 2, 3, 5}; + EXPECT(not rocm::equal(a.begin(), a.end(), b.begin(), [](int x, int y) { return x == y; })); +} +TEST_CASE(equal_empty) +{ + empty_range a = {}; + empty_range b = {}; + EXPECT(rocm::equal(a.begin(), a.end(), b.begin(), [](int x, int y) { return x == y; })); +} +TEST_CASE(equal_custom_predicate) +{ + rocm::array a = {1, 2, 3}; + rocm::array b = {2, 4, 6}; + EXPECT(rocm::equal(a.begin(), a.end(), b.begin(), [](int x, int y) { return x * 2 == y; })); +} + +TEST_CASE(iota_basic) +{ + rocm::array arr = {0, 0, 0, 0, 0}; + rocm::iota(arr.begin(), arr.end(), 10); + rocm::array expected = {10, 11, 12, 13, 14}; + EXPECT(arr == expected); +} +TEST_CASE(iota_empty) +{ + empty_range arr = {}; + rocm::iota(arr.begin(), arr.end(), 5); +} +TEST_CASE(iota_single) +{ + rocm::array arr = {0}; + rocm::iota(arr.begin(), arr.end(), 42); + EXPECT(arr[0] == 42); +} +TEST_CASE(iota_negative) +{ + rocm::array arr = {0, 0, 0}; + rocm::iota(arr.begin(), arr.end(), -5); + rocm::array expected = {-5, -4, -3}; + EXPECT(arr == expected); +} + +TEST_CASE(min_element_basic) +{ + rocm::array arr = {3, 1, 4, 1, 5}; + auto* result = rocm::min_element(arr.begin(), arr.end(), rocm::less<>{}); + EXPECT(result == arr.begin() + 1); +} +TEST_CASE(min_element_empty) +{ + empty_range arr = {}; + auto* result = rocm::min_element(arr.begin(), arr.end(), rocm::less<>{}); + EXPECT(result == arr.end()); +} +TEST_CASE(min_element_single) +{ + rocm::array arr = {42}; + auto* result = rocm::min_element(arr.begin(), arr.end(), rocm::less<>{}); + EXPECT(result == arr.begin()); +} +TEST_CASE(min_element_all_equal) +{ + rocm::array arr = {5, 5, 5, 5}; + auto* result = rocm::min_element(arr.begin(), arr.end(), rocm::less<>{}); + EXPECT(result == arr.begin()); +} +TEST_CASE(min_element_custom_compare) +{ + rocm::array arr = {1, 2, 3, 4}; + auto* result = rocm::min_element(arr.begin(), arr.end(), rocm::greater<>{}); + EXPECT(result == arr.begin() + 3); +} + +TEST_CASE(rotate_left_by_two) +{ + rocm::array arr = {1, 2, 3, 4, 5, 6}; + auto* result = rocm::rotate(arr.begin(), arr.begin() + 2, arr.end()); + rocm::array expected = {3, 4, 5, 6, 1, 2}; + EXPECT(arr == expected); + EXPECT(result == arr.begin() + 4); +} +TEST_CASE(rotate_right_by_one) +{ + rocm::array arr = {1, 2, 3, 4, 5}; + auto* result = rocm::rotate(arr.begin(), arr.end() - 1, arr.end()); + rocm::array expected = {5, 1, 2, 3, 4}; + EXPECT(arr == expected); + EXPECT(result == arr.begin() + 1); +} +TEST_CASE(rotate_half_array) +{ + rocm::array arr = {1, 2, 3, 4, 5, 6, 7, 8}; + auto* result = rocm::rotate(arr.begin(), arr.begin() + 4, arr.end()); + rocm::array expected = {5, 6, 7, 8, 1, 2, 3, 4}; + EXPECT(arr == expected); + EXPECT(result == arr.begin() + 4); +} +TEST_CASE(rotate_almost_full) +{ + rocm::array arr = {1, 2, 3, 4, 5}; + auto* result = rocm::rotate(arr.begin(), arr.begin() + 4, arr.end()); + rocm::array expected = {5, 1, 2, 3, 4}; + EXPECT(arr == expected); + EXPECT(result == arr.begin() + 1); +} +TEST_CASE(rotate_two_elements) +{ + rocm::array arr = {1, 2}; + auto* result = rocm::rotate(arr.begin(), arr.begin() + 1, arr.end()); + rocm::array expected = {2, 1}; + EXPECT(arr == expected); + EXPECT(result == arr.begin() + 1); +} +TEST_CASE(rotate_partial_range) +{ + rocm::array arr = {1, 2, 3, 4, 5, 6, 7}; + auto* result = rocm::rotate(arr.begin() + 1, arr.begin() + 3, arr.begin() + 5); + rocm::array expected = {1, 4, 5, 2, 3, 6, 7}; + EXPECT(arr == expected); + EXPECT(result == arr.begin() + 3); +} +TEST_CASE(rotate_with_duplicates) +{ + rocm::array arr = {1, 1, 2, 2, 3, 3}; + auto* result = rocm::rotate(arr.begin(), arr.begin() + 2, arr.end()); + rocm::array expected = {2, 2, 3, 3, 1, 1}; + EXPECT(arr == expected); + EXPECT(result == arr.begin() + 4); +} +TEST_CASE(rotate_stress_test_large_shift) +{ + rocm::array arr = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + auto* result = rocm::rotate(arr.begin(), arr.begin() + 7, arr.end()); + rocm::array expected = {7, 8, 9, 0, 1, 2, 3, 4, 5, 6}; + EXPECT(arr == expected); + EXPECT(result == arr.begin() + 3); +} +TEST_CASE(rotate_edge_case_middle_equals_first) +{ + rocm::array arr = {1, 2, 3, 4}; + rocm::array original = arr; + auto* result = rocm::rotate(arr.begin(), arr.begin(), arr.end()); + EXPECT(arr == original); + EXPECT(result == arr.end()); +} +TEST_CASE(rotate_edge_case_middle_equals_last) +{ + rocm::array arr = {1, 2, 3, 4}; + rocm::array original = arr; + auto* result = rocm::rotate(arr.begin(), arr.end(), arr.end()); + EXPECT(arr == original); + EXPECT(result == arr.begin()); +} + +TEST_CASE(upper_bound_basic) +{ + rocm::array arr = {1, 2, 2, 3, 4}; + auto* result = rocm::upper_bound(arr.begin(), arr.end(), 2, rocm::less<>{}); + EXPECT(result == arr.begin() + 3); +} +TEST_CASE(upper_bound_not_found) +{ + rocm::array arr = {1, 2, 3, 4}; + auto* result = rocm::upper_bound(arr.begin(), arr.end(), 5, rocm::less<>{}); + EXPECT(result == arr.end()); +} +TEST_CASE(upper_bound_first_element) +{ + rocm::array arr = {1, 2, 3, 4}; + auto* result = rocm::upper_bound(arr.begin(), arr.end(), 0, rocm::less<>{}); + EXPECT(result == arr.begin()); +} +TEST_CASE(upper_bound_empty) +{ + empty_range arr = {}; + auto* result = rocm::upper_bound(arr.begin(), arr.end(), 5, rocm::less<>{}); + EXPECT(result == arr.end()); +} +TEST_CASE(upper_bound_all_equal) +{ + rocm::array arr = {2, 2, 2}; + auto* result = rocm::upper_bound(arr.begin(), arr.end(), 2, rocm::less<>{}); + EXPECT(result == arr.end()); +} +TEST_CASE(upper_bound_multiple_duplicates) +{ + rocm::array arr = {1, 2, 2, 2, 2, 3, 4, 5}; + auto* result = rocm::upper_bound(arr.begin(), arr.end(), 2, rocm::less<>{}); + EXPECT(result == arr.begin() + 5); +} +TEST_CASE(upper_bound_all_smaller) +{ + rocm::array arr = {1, 2, 3, 4, 5}; + auto* result = rocm::upper_bound(arr.begin(), arr.end(), 0, rocm::less<>{}); + EXPECT(result == arr.begin()); +} +TEST_CASE(upper_bound_all_larger) +{ + rocm::array arr = {1, 2, 3, 4, 5}; + auto* result = rocm::upper_bound(arr.begin(), arr.end(), 10, rocm::less<>{}); + EXPECT(result == arr.end()); +} +TEST_CASE(upper_bound_single_element_match) +{ + rocm::array arr = {5}; + auto* result = rocm::upper_bound(arr.begin(), arr.end(), 5, rocm::less<>{}); + EXPECT(result == arr.end()); +} +TEST_CASE(upper_bound_single_element_smaller) +{ + rocm::array arr = {5}; + auto* result = rocm::upper_bound(arr.begin(), arr.end(), 3, rocm::less<>{}); + EXPECT(result == arr.begin()); +} +TEST_CASE(upper_bound_single_element_larger) +{ + rocm::array arr = {5}; + auto* result = rocm::upper_bound(arr.begin(), arr.end(), 7, rocm::less<>{}); + EXPECT(result == arr.end()); +} +TEST_CASE(upper_bound_beginning_duplicates) +{ + rocm::array arr = {1, 1, 1, 4, 5, 6}; + auto* result = rocm::upper_bound(arr.begin(), arr.end(), 1, rocm::less<>{}); + EXPECT(result == arr.begin() + 3); +} +TEST_CASE(upper_bound_end_duplicates) +{ + rocm::array arr = {1, 2, 3, 5, 5, 5}; + auto* result = rocm::upper_bound(arr.begin(), arr.end(), 5, rocm::less<>{}); + EXPECT(result == arr.end()); +} +TEST_CASE(upper_bound_middle_value) +{ + rocm::array arr = {1, 3, 5, 7, 9, 11, 13}; + auto* result = rocm::upper_bound(arr.begin(), arr.end(), 7, rocm::less<>{}); + EXPECT(result == arr.begin() + 4); +} +TEST_CASE(upper_bound_partial_range) +{ + rocm::array arr = {1, 2, 3, 4, 5, 6, 7, 8}; + auto* result = rocm::upper_bound(arr.begin() + 2, arr.begin() + 6, 4, rocm::less<>{}); + EXPECT(result == arr.begin() + 4); +} +TEST_CASE(upper_bound_reverse_comparator) +{ + rocm::array arr = {5, 4, 3, 2, 1}; + auto* result = rocm::upper_bound(arr.begin(), arr.end(), 3, rocm::greater<>{}); + EXPECT(result == arr.begin() + 3); +} +TEST_CASE(upper_bound_large_array_power_of_two) +{ + rocm::array arr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; + auto* result = rocm::upper_bound(arr.begin(), arr.end(), 8, rocm::less<>{}); + EXPECT(result == arr.begin() + 8); +} +TEST_CASE(upper_bound_stress_binary_search) +{ + rocm::array arr = {2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30}; + auto* result = rocm::upper_bound(arr.begin(), arr.end(), 16, rocm::less<>{}); + EXPECT(result == arr.begin() + 8); +} +TEST_CASE(upper_bound_stress_test_boundary) +{ + rocm::array arr = {1, 2, 3, 4, 5, 6, 7}; + for(int i = 1; i <= 7; ++i) + { + auto* result = rocm::upper_bound(arr.begin(), arr.end(), i, rocm::less<>{}); + EXPECT(result == arr.begin() + i); + } +} + +TEST_CASE(sort_basic) +{ + rocm::array arr = {5, 2, 8, 1, 9}; + rocm::sort(arr.begin(), arr.end(), rocm::less<>{}); + rocm::array expected = {1, 2, 5, 8, 9}; + EXPECT(arr == expected); +} +TEST_CASE(sort_already_sorted) +{ + rocm::array arr = {1, 2, 3, 4}; + rocm::array original = arr; + rocm::sort(arr.begin(), arr.end(), rocm::less<>{}); + EXPECT(arr == original); +} +TEST_CASE(sort_reverse_sorted) +{ + rocm::array arr = {4, 3, 2, 1}; + rocm::sort(arr.begin(), arr.end(), rocm::less<>{}); + rocm::array expected = {1, 2, 3, 4}; + EXPECT(arr == expected); +} +TEST_CASE(sort_duplicates) +{ + rocm::array arr = {3, 1, 4, 1, 5, 2}; + rocm::sort(arr.begin(), arr.end(), rocm::less<>{}); + rocm::array expected = {1, 1, 2, 3, 4, 5}; + EXPECT(arr == expected); +} +TEST_CASE(sort_empty) +{ + empty_range arr = {}; + rocm::sort(arr.begin(), arr.end(), rocm::less<>{}); +} +TEST_CASE(sort_single) +{ + rocm::array arr = {42}; + rocm::array original = arr; + rocm::sort(arr.begin(), arr.end(), rocm::less<>{}); + EXPECT(arr == original); +} +TEST_CASE(sort_default_comparator) +{ + rocm::array arr = {3, 1, 4, 2}; + rocm::sort(arr.begin(), arr.end()); + rocm::array expected = {1, 2, 3, 4}; + EXPECT(arr == expected); +} + +TEST_CASE(stable_sort_basic) +{ + rocm::array arr = {5, 2, 8, 1, 9}; + rocm::stable_sort(arr.begin(), arr.end(), rocm::less<>{}); + rocm::array expected = {1, 2, 5, 8, 9}; + EXPECT(arr == expected); +} +TEST_CASE(stable_sort_empty) +{ + empty_range arr = {}; + rocm::stable_sort(arr.begin(), arr.end(), rocm::less<>{}); +} +TEST_CASE(stable_sort_single) +{ + rocm::array arr = {42}; + rocm::array original = arr; + rocm::stable_sort(arr.begin(), arr.end(), rocm::less<>{}); + EXPECT(arr == original); +} +TEST_CASE(stable_sort_already_sorted) +{ + rocm::array arr = {1, 2, 3, 4}; + rocm::array original = arr; + rocm::stable_sort(arr.begin(), arr.end(), rocm::less<>{}); + EXPECT(arr == original); +} +TEST_CASE(stable_sort_default_comparator) +{ + rocm::array arr = {3, 1, 4, 2}; + rocm::stable_sort(arr.begin(), arr.end()); + rocm::array expected = {1, 2, 3, 4}; + EXPECT(arr == expected); +} + +TEST_CASE(merge_basic) +{ + rocm::array arr1 = {1, 3, 5}; + rocm::array arr2 = {2, 4, 6}; + rocm::array result = {0, 0, 0, 0, 0, 0}; + rocm::merge(arr1.begin(), arr1.end(), arr2.begin(), arr2.end(), result.begin(), rocm::less<>{}); + rocm::array expected = {1, 2, 3, 4, 5, 6}; + EXPECT(result == expected); +} +TEST_CASE(merge_empty_first) +{ + empty_range arr1 = {}; + rocm::array arr2 = {1, 2, 3}; + rocm::array result = {0, 0, 0}; + rocm::merge(arr1.begin(), arr1.end(), arr2.begin(), arr2.end(), result.begin(), rocm::less<>{}); + EXPECT(result == arr2); +} +TEST_CASE(merge_empty_second) +{ + rocm::array arr1 = {1, 2, 3}; + empty_range arr2 = {}; + rocm::array result = {0, 0, 0}; + rocm::merge(arr1.begin(), arr1.end(), arr2.begin(), arr2.end(), result.begin(), rocm::less<>{}); + EXPECT(result == arr1); +} +TEST_CASE(merge_both_empty) +{ + empty_range arr1 = {}; + empty_range arr2 = {}; + empty_range result = {}; + auto* end_it = rocm::merge( + arr1.begin(), arr1.end(), arr2.begin(), arr2.end(), result.begin(), rocm::less<>{}); + EXPECT(end_it == result.end()); +} +TEST_CASE(merge_overlapping_ranges) +{ + rocm::array arr1 = {1, 3, 5, 7}; + rocm::array arr2 = {2, 6}; + rocm::array result = {0, 0, 0, 0, 0, 0}; + rocm::merge(arr1.begin(), arr1.end(), arr2.begin(), arr2.end(), result.begin(), rocm::less<>{}); + rocm::array expected = {1, 2, 3, 5, 6, 7}; + EXPECT(result == expected); +} +TEST_CASE(merge_duplicates) +{ + rocm::array arr1 = {1, 2, 3}; + rocm::array arr2 = {2, 3, 4}; + rocm::array result = {0, 0, 0, 0, 0, 0}; + rocm::merge(arr1.begin(), arr1.end(), arr2.begin(), arr2.end(), result.begin(), rocm::less<>{}); + rocm::array expected = {1, 2, 2, 3, 3, 4}; + EXPECT(result == expected); +} +// Additional merge tests (extensive) +TEST_CASE(merge_different_sizes) +{ + rocm::array arr1 = {1, 5}; + rocm::array arr2 = {2, 3, 4, 6}; + rocm::array result = {0, 0, 0, 0, 0, 0}; + rocm::merge(arr1.begin(), arr1.end(), arr2.begin(), arr2.end(), result.begin(), rocm::less<>{}); + rocm::array expected = {1, 2, 3, 4, 5, 6}; + EXPECT(result == expected); +} +TEST_CASE(merge_first_all_smaller) +{ + rocm::array arr1 = {1, 2, 3}; + rocm::array arr2 = {4, 5, 6}; + rocm::array result = {0, 0, 0, 0, 0, 0}; + rocm::merge(arr1.begin(), arr1.end(), arr2.begin(), arr2.end(), result.begin(), rocm::less<>{}); + rocm::array expected = {1, 2, 3, 4, 5, 6}; + EXPECT(result == expected); +} +TEST_CASE(merge_first_all_larger) +{ + rocm::array arr1 = {4, 5, 6}; + rocm::array arr2 = {1, 2, 3}; + rocm::array result = {0, 0, 0, 0, 0, 0}; + rocm::merge(arr1.begin(), arr1.end(), arr2.begin(), arr2.end(), result.begin(), rocm::less<>{}); + rocm::array expected = {1, 2, 3, 4, 5, 6}; + EXPECT(result == expected); +} +TEST_CASE(merge_interleaved) +{ + rocm::array arr1 = {1, 3, 5, 7}; + rocm::array arr2 = {2, 4, 6, 8}; + rocm::array result = {0, 0, 0, 0, 0, 0, 0, 0}; + rocm::merge(arr1.begin(), arr1.end(), arr2.begin(), arr2.end(), result.begin(), rocm::less<>{}); + rocm::array expected = {1, 2, 3, 4, 5, 6, 7, 8}; + EXPECT(result == expected); +} +TEST_CASE(merge_many_duplicates) +{ + rocm::array arr1 = {1, 1, 2, 2}; + rocm::array arr2 = {1, 2, 2, 3}; + rocm::array result = {0, 0, 0, 0, 0, 0, 0, 0}; + rocm::merge(arr1.begin(), arr1.end(), arr2.begin(), arr2.end(), result.begin(), rocm::less<>{}); + rocm::array expected = {1, 1, 1, 2, 2, 2, 2, 3}; + EXPECT(result == expected); +} +TEST_CASE(merge_all_equal_elements) +{ + rocm::array arr1 = {5, 5, 5}; + rocm::array arr2 = {5, 5}; + rocm::array result = {0, 0, 0, 0, 0}; + rocm::merge(arr1.begin(), arr1.end(), arr2.begin(), arr2.end(), result.begin(), rocm::less<>{}); + rocm::array expected = {5, 5, 5, 5, 5}; + EXPECT(result == expected); +} +TEST_CASE(merge_single_elements) +{ + rocm::array arr1 = {3}; + rocm::array arr2 = {1}; + rocm::array result = {0, 0}; + rocm::merge(arr1.begin(), arr1.end(), arr2.begin(), arr2.end(), result.begin(), rocm::less<>{}); + rocm::array expected = {1, 3}; + EXPECT(result == expected); +} +TEST_CASE(merge_one_single_element) +{ + rocm::array arr1 = {3}; + rocm::array arr2 = {1, 2, 4, 5}; + rocm::array result = {0, 0, 0, 0, 0}; + rocm::merge(arr1.begin(), arr1.end(), arr2.begin(), arr2.end(), result.begin(), rocm::less<>{}); + rocm::array expected = {1, 2, 3, 4, 5}; + EXPECT(result == expected); +} +TEST_CASE(merge_reverse_order) +{ + rocm::array arr1 = {6, 4, 2}; + rocm::array arr2 = {5, 3, 1}; + rocm::array result = {0, 0, 0, 0, 0, 0}; + rocm::merge( + arr1.begin(), arr1.end(), arr2.begin(), arr2.end(), result.begin(), rocm::greater<>{}); + rocm::array expected = {6, 5, 4, 3, 2, 1}; + EXPECT(result == expected); +} +TEST_CASE(merge_negative_numbers) +{ + rocm::array arr1 = {-5, -2, 1}; + rocm::array arr2 = {-3, 0, 3}; + rocm::array result = {0, 0, 0, 0, 0, 0}; + rocm::merge(arr1.begin(), arr1.end(), arr2.begin(), arr2.end(), result.begin(), rocm::less<>{}); + rocm::array expected = {-5, -3, -2, 0, 1, 3}; + EXPECT(result == expected); +} +TEST_CASE(merge_large_difference) +{ + rocm::array arr1 = {1, 1000, 2000}; + rocm::array arr2 = {2, 500, 1500}; + rocm::array result = {0, 0, 0, 0, 0, 0}; + rocm::merge(arr1.begin(), arr1.end(), arr2.begin(), arr2.end(), result.begin(), rocm::less<>{}); + rocm::array expected = {1, 2, 500, 1000, 1500, 2000}; + EXPECT(result == expected); +} +TEST_CASE(merge_partial_ranges) +{ + rocm::array arr1 = {0, 1, 2, 3, 4, 5, 6, 7}; + rocm::array arr2 = {10, 11, 12, 13, 14, 15}; + rocm::array result = {0, 0, 0, 0, 0}; + rocm::merge(arr1.begin() + 2, + arr1.begin() + 5, + arr2.begin() + 1, + arr2.begin() + 3, + result.begin(), + rocm::less<>{}); + rocm::array expected = {2, 3, 4, 11, 12}; + EXPECT(result == expected); +} +TEST_CASE(merge_stability_test) +{ + rocm::array arr1 = {1, 3, 5, 7}; + rocm::array arr2 = {2, 3, 6, 7}; + rocm::array result = {0, 0, 0, 0, 0, 0, 0, 0}; + rocm::merge(arr1.begin(), arr1.end(), arr2.begin(), arr2.end(), result.begin(), rocm::less<>{}); + rocm::array expected = {1, 2, 3, 3, 5, 6, 7, 7}; + EXPECT(result == expected); +} + +TEST_CASE(accumulate_default_op_basic) +{ + rocm::array arr = {1, 2, 3, 4}; + auto sum = rocm::accumulate(arr.begin(), arr.end(), 0); + EXPECT(sum == 10); +} +TEST_CASE(accumulate_default_op_empty) +{ + empty_range arr = {}; + auto sum = rocm::accumulate(arr.begin(), arr.end(), 42); + EXPECT(sum == 42); +} +TEST_CASE(accumulate_default_op_single) +{ + rocm::array arr = {7}; + auto sum = rocm::accumulate(arr.begin(), arr.end(), 5); + EXPECT(sum == 12); +} + +TEST_CASE(transform_binary_basic) +{ + rocm::array a = {1, 2, 3, 4}; + rocm::array b = {10, 20, 30, 40}; + rocm::array out = {0, 0, 0, 0}; + rocm::transform(a.begin(), a.end(), b.begin(), out.begin(), [](int x, int y) { return x + y; }); + rocm::array expected = {11, 22, 33, 44}; + EXPECT(out == expected); +} +TEST_CASE(transform_binary_multiply) +{ + rocm::array a = {2, 3, 4}; + rocm::array b = {5, 6, 7}; + rocm::array out = {0, 0, 0}; + rocm::transform(a.begin(), a.end(), b.begin(), out.begin(), [](int x, int y) { return x * y; }); + rocm::array expected = {10, 18, 28}; + EXPECT(out == expected); +} +TEST_CASE(transform_binary_empty) +{ + empty_range a = {}; + empty_range b = {}; + empty_range out = {}; + auto* result = rocm::transform( + a.begin(), a.end(), b.begin(), out.begin(), [](int x, int y) { return x + y; }); + EXPECT(result == out.end()); +} + +TEST_CASE(is_sorted_until_default_sorted) +{ + rocm::array arr = {1, 2, 3, 4}; + auto* result = rocm::is_sorted_until(arr.begin(), arr.end()); + EXPECT(result == arr.end()); +} +TEST_CASE(is_sorted_until_default_unsorted) +{ + rocm::array arr = {1, 2, 4, 3, 5}; + auto* result = rocm::is_sorted_until(arr.begin(), arr.end()); + EXPECT(result == arr.begin() + 3); +} +TEST_CASE(is_sorted_until_default_single) +{ + rocm::array arr = {42}; + auto* result = rocm::is_sorted_until(arr.begin(), arr.end()); + EXPECT(result == arr.end()); +} + +TEST_CASE(is_sorted_default_true) +{ + rocm::array arr = {1, 2, 3, 4}; + EXPECT(rocm::is_sorted(arr.begin(), arr.end())); +} +TEST_CASE(is_sorted_default_false) +{ + rocm::array arr = {1, 3, 2, 4}; + EXPECT(not rocm::is_sorted(arr.begin(), arr.end())); +} +TEST_CASE(is_sorted_default_empty) +{ + empty_range arr = {}; + EXPECT(rocm::is_sorted(arr.begin(), arr.end())); +} + +TEST_CASE(search_predicate_found) +{ + rocm::array haystack = {1, 2, 3, 4, 3, 4}; + rocm::array needle = {13, 14}; + auto* result = rocm::search( + haystack.begin(), haystack.end(), needle.begin(), needle.end(), [](int x, int y) { + return x % 10 == y % 10; + }); + EXPECT(result == haystack.begin() + 2); +} +TEST_CASE(search_predicate_not_found) +{ + rocm::array haystack = {1, 2, 3, 4, 5}; + rocm::array needle = {16, 17}; + auto* result = rocm::search( + haystack.begin(), haystack.end(), needle.begin(), needle.end(), [](int x, int y) { + return x % 10 == y % 10; + }); + EXPECT(result == haystack.end()); +} +TEST_CASE(search_predicate_empty_needle) +{ + rocm::array haystack = {1, 2, 3}; + empty_range needle = {}; + auto* result = rocm::search( + haystack.begin(), haystack.end(), needle.begin(), needle.end(), [](int x, int y) { + return x == y; + }); + EXPECT(result == haystack.begin()); +} + +TEST_CASE(equal_default_true) +{ + rocm::array a = {1, 2, 3, 4}; + rocm::array b = {1, 2, 3, 4}; + EXPECT(rocm::equal(a.begin(), a.end(), b.begin())); +} +TEST_CASE(equal_default_false) +{ + rocm::array a = {1, 2, 3, 4}; + rocm::array b = {1, 2, 3, 5}; + EXPECT(not rocm::equal(a.begin(), a.end(), b.begin())); +} +TEST_CASE(equal_default_empty) +{ + empty_range a = {}; + empty_range b = {}; + EXPECT(rocm::equal(a.begin(), a.end(), b.begin())); +} + +TEST_CASE(min_element_default_basic) +{ + rocm::array arr = {3, 1, 4, 1, 5}; + auto* result = rocm::min_element(arr.begin(), arr.end()); + EXPECT(result == arr.begin() + 1); +} +TEST_CASE(min_element_default_single) +{ + rocm::array arr = {42}; + auto* result = rocm::min_element(arr.begin(), arr.end()); + EXPECT(result == arr.begin()); +} +TEST_CASE(min_element_default_all_equal) +{ + rocm::array arr = {5, 5, 5, 5}; + auto* result = rocm::min_element(arr.begin(), arr.end()); + EXPECT(result == arr.begin()); +} + +TEST_CASE(max_element_basic) +{ + rocm::array arr = {3, 1, 4, 1, 5}; + auto* result = rocm::max_element(arr.begin(), arr.end(), rocm::less<>{}); + EXPECT(result == arr.begin() + 4); +} +TEST_CASE(max_element_default) +{ + rocm::array arr = {3, 1, 4, 1, 5}; + auto* result = rocm::max_element(arr.begin(), arr.end()); + EXPECT(result == arr.begin() + 4); +} +TEST_CASE(max_element_empty) +{ + empty_range arr = {}; + auto* result = rocm::max_element(arr.begin(), arr.end()); + EXPECT(result == arr.end()); +} +TEST_CASE(max_element_single) +{ + rocm::array arr = {42}; + auto* result = rocm::max_element(arr.begin(), arr.end()); + EXPECT(result == arr.begin()); +} +TEST_CASE(max_element_all_equal) +{ + rocm::array arr = {5, 5, 5, 5}; + auto* result = rocm::max_element(arr.begin(), arr.end()); + EXPECT(result == arr.begin()); +} +TEST_CASE(max_element_custom_compare) +{ + rocm::array arr = {1, 2, 3, 4}; + auto* result = rocm::max_element(arr.begin(), arr.end(), rocm::greater<>{}); + EXPECT(result == arr.begin()); +} + +TEST_CASE(upper_bound_default_basic) +{ + rocm::array arr = {1, 2, 2, 3, 4}; + auto* result = rocm::upper_bound(arr.begin(), arr.end(), 2); + EXPECT(result == arr.begin() + 3); +} +TEST_CASE(upper_bound_default_not_found) +{ + rocm::array arr = {1, 2, 3, 4}; + auto* result = rocm::upper_bound(arr.begin(), arr.end(), 5); + EXPECT(result == arr.end()); +} +TEST_CASE(upper_bound_default_first_element) +{ + rocm::array arr = {1, 2, 3, 4}; + auto* result = rocm::upper_bound(arr.begin(), arr.end(), 0); + EXPECT(result == arr.begin()); +} + +TEST_CASE(lower_bound_basic) +{ + rocm::array arr = {1, 2, 2, 3, 4}; + auto* result = rocm::lower_bound(arr.begin(), arr.end(), 2, rocm::less<>{}); + EXPECT(result == arr.begin() + 1); +} +TEST_CASE(lower_bound_default) +{ + rocm::array arr = {1, 2, 2, 3, 4}; + auto* result = rocm::lower_bound(arr.begin(), arr.end(), 2); + EXPECT(result == arr.begin() + 1); +} +TEST_CASE(lower_bound_not_found) +{ + rocm::array arr = {1, 2, 3, 4}; + auto* result = rocm::lower_bound(arr.begin(), arr.end(), 5); + EXPECT(result == arr.end()); +} +TEST_CASE(lower_bound_all_equal) +{ + rocm::array arr = {2, 2, 2}; + auto* result = rocm::lower_bound(arr.begin(), arr.end(), 2); + EXPECT(result == arr.begin()); +} +TEST_CASE(lower_bound_duplicates) +{ + rocm::array arr = {1, 2, 2, 2, 2, 3, 4, 5}; + auto* result = rocm::lower_bound(arr.begin(), arr.end(), 2); + EXPECT(result == arr.begin() + 1); +} +TEST_CASE(lower_bound_empty) +{ + empty_range arr = {}; + auto* result = rocm::lower_bound(arr.begin(), arr.end(), 5); + EXPECT(result == arr.end()); +} +TEST_CASE(lower_bound_first_element) +{ + rocm::array arr = {1, 2, 3, 4}; + auto* result = rocm::lower_bound(arr.begin(), arr.end(), 0); + EXPECT(result == arr.begin()); +} +TEST_CASE(lower_bound_single_match) +{ + rocm::array arr = {5}; + auto* result = rocm::lower_bound(arr.begin(), arr.end(), 5); + EXPECT(result == arr.begin()); +} +TEST_CASE(lower_bound_single_larger) +{ + rocm::array arr = {5}; + auto* result = rocm::lower_bound(arr.begin(), arr.end(), 7); + EXPECT(result == arr.end()); +} + +TEST_CASE(swap_self_assignment) +{ + int x = 42; + rocm::swap(x, x); + EXPECT(x == 42); +} +TEST_CASE(find_if_predicate_consistency) +{ + rocm::array arr = {1, 2, 3, 4}; + int call_count = 0; + auto predicate = [&call_count](int x) { + call_count++; + return x > 2; + }; + auto* result = rocm::find_if(arr.begin(), arr.end(), predicate); + EXPECT(result == arr.begin() + 2); + EXPECT(call_count == 3); +} diff --git a/test/gpu/kernels/rocm/array.cpp b/test/gpu/kernels/rocm/array.cpp new file mode 100644 index 00000000000..afbc10598a1 --- /dev/null +++ b/test/gpu/kernels/rocm/array.cpp @@ -0,0 +1,501 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2025-2026 Advanced Micro Devices, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#include +#include + +// ---- Aggregate initialization ---- + +TEST_CASE(aggregate_init) +{ + rocm::array a = {1, 2, 3}; + EXPECT(a[0] == 1); + EXPECT(a[1] == 2); + EXPECT(a[2] == 3); +} + +TEST_CASE(aggregate_init_single) +{ + rocm::array a = {42}; + EXPECT(a[0] == 42); +} + +TEST_CASE(default_init) +{ + rocm::array a = {}; + EXPECT(a[0] == 0); + EXPECT(a[1] == 0); + EXPECT(a[2] == 0); +} + +// ---- CTAD ---- +#ifdef MIGRAPHX_WORKAROUND_BROKEN_DEDUCTION_GUIDE +TEST_CASE(ctad) {} + +TEST_CASE(ctad_single) {} +#else +TEST_CASE(ctad) +{ + rocm::array a = {1, 2, 3, 4}; + EXPECT(a.size() == 4); + EXPECT(a[0] == 1); + EXPECT(a[3] == 4); +} + +TEST_CASE(ctad_single) +{ + rocm::array a = {99}; + EXPECT(a.size() == 1); + EXPECT(a[0] == 99); +} +#endif + +// ---- size / max_size / empty ---- + +TEST_CASE(size) +{ + rocm::array a = {1, 2, 3, 4, 5}; + EXPECT(a.size() == 5); + EXPECT(a.max_size() == 5); + EXPECT(not a.empty()); +} + +TEST_CASE(size_zero) +{ + rocm::array a = {}; + EXPECT(a.size() == 0); + EXPECT(a.max_size() == 0); + EXPECT(a.empty()); +} + +// ---- element access: operator[] ---- + +TEST_CASE(subscript_read) +{ + rocm::array a = {10, 20, 30, 40}; + EXPECT(a[0] == 10); + EXPECT(a[3] == 40); +} + +TEST_CASE(subscript_write) +{ + rocm::array a = {1, 2, 3}; + a[1] = 99; + EXPECT(a[1] == 99); +} + +TEST_CASE(subscript_const) +{ + const rocm::array a = {5, 6, 7}; + EXPECT(a[0] == 5); + EXPECT(a[2] == 7); +} + +// ---- element access: at ---- + +TEST_CASE(at_read) +{ + rocm::array a = {10, 20, 30}; + EXPECT(a.at(0) == 10); + EXPECT(a.at(2) == 30); +} + +TEST_CASE(at_write) +{ + rocm::array a = {1, 2, 3}; + a.at(0) = 77; + EXPECT(a.at(0) == 77); +} + +// ---- element access: front / back ---- + +TEST_CASE(front) +{ + rocm::array a = {10, 20, 30, 40}; + EXPECT(a.front() == 10); +} + +TEST_CASE(back) +{ + rocm::array a = {10, 20, 30, 40}; + EXPECT(a.back() == 40); +} + +TEST_CASE(front_write) +{ + rocm::array a = {1, 2, 3}; + a.front() = 99; + EXPECT(a[0] == 99); +} + +TEST_CASE(back_write) +{ + rocm::array a = {1, 2, 3}; + a.back() = 99; + EXPECT(a[2] == 99); +} + +TEST_CASE(front_back_const) +{ + const rocm::array a = {5, 6, 7}; + EXPECT(a.front() == 5); + EXPECT(a.back() == 7); +} + +// ---- data ---- + +TEST_CASE(data_non_null) +{ + rocm::array a = {1, 2, 3}; + EXPECT(a.data() != nullptr); + EXPECT(a.data() == a.begin()); +} + +TEST_CASE(data_const) +{ + const rocm::array a = {1, 2, 3}; + EXPECT(a.data() != nullptr); + EXPECT(*a.data() == 1); +} + +TEST_CASE(data_zero_size) +{ + rocm::array a = {}; + EXPECT(a.data() == nullptr); +} + +// ---- fill ---- + +TEST_CASE(fill) +{ + rocm::array a = {}; + a.fill(42); + EXPECT(a[0] == 42); + EXPECT(a[1] == 42); + EXPECT(a[2] == 42); + EXPECT(a[3] == 42); +} + +TEST_CASE(fill_overwrite) +{ + rocm::array a = {1, 2, 3}; + a.fill(0); + EXPECT(a[0] == 0); + EXPECT(a[1] == 0); + EXPECT(a[2] == 0); +} + +// ---- swap ---- + +TEST_CASE(swap_member) +{ + rocm::array a = {1, 2, 3}; + rocm::array b = {4, 5, 6}; + a.swap(b); + EXPECT(a[0] == 4); + EXPECT(a[1] == 5); + EXPECT(a[2] == 6); + EXPECT(b[0] == 1); + EXPECT(b[1] == 2); + EXPECT(b[2] == 3); +} + +TEST_CASE(swap_free) +{ + rocm::array a = {10, 20, 30}; + rocm::array b = {40, 50, 60}; + rocm::swap(a, b); + EXPECT(a[0] == 40); + EXPECT(b[0] == 10); +} + +// ---- iterators: begin / end ---- + +TEST_CASE(begin_end) +{ + rocm::array a = {1, 2, 3}; + auto* it = a.begin(); + EXPECT(*it == 1); + ++it; + EXPECT(*it == 2); + ++it; + EXPECT(*it == 3); + ++it; + EXPECT(it == a.end()); +} + +TEST_CASE(begin_end_const) +{ + const rocm::array a = {10, 20, 30}; + const auto* it = a.begin(); + EXPECT(*it == 10); + EXPECT(*(a.end() - 1) == 30); +} + +TEST_CASE(cbegin_cend) +{ + rocm::array a = {1, 2, 3}; + const auto* it = a.cbegin(); + EXPECT(*it == 1); + EXPECT(a.cend() - a.cbegin() == 3); +} + +// ---- iterators: rbegin / rend ---- + +TEST_CASE(rbegin_rend) +{ + rocm::array a = {10, 20, 30, 40}; + auto it = a.rbegin(); + EXPECT(*it == 40); + ++it; + EXPECT(*it == 30); + ++it; + EXPECT(*it == 20); + ++it; + EXPECT(*it == 10); + ++it; + EXPECT(it == a.rend()); +} + +TEST_CASE(crbegin_crend) +{ + const rocm::array a = {5, 6, 7}; + auto it = a.crbegin(); + EXPECT(*it == 7); + EXPECT(a.crend() - a.crbegin() == 3); +} + +// ---- iterators: zero-size ---- + +TEST_CASE(iterators_zero_size) +{ + rocm::array a = {}; + EXPECT(a.begin() == a.end()); + EXPECT(a.cbegin() == a.cend()); +} + +// ---- comparison: operator== / operator!= ---- + +TEST_CASE(equal) +{ + rocm::array a = {1, 2, 3}; + rocm::array b = {1, 2, 3}; + EXPECT(a == b); + EXPECT(not(a != b)); +} + +TEST_CASE(not_equal) +{ + rocm::array a = {1, 2, 3}; + rocm::array b = {1, 2, 4}; + EXPECT(a != b); + EXPECT(not(a == b)); +} + +TEST_CASE(equal_zero_size) +{ + rocm::array a = {}; + rocm::array b = {}; + EXPECT(a == b); + EXPECT(not(a != b)); +} + +// ---- comparison: operator< / operator> / operator<= / operator>= ---- + +TEST_CASE(less_than) +{ + rocm::array a = {1, 2, 3}; + rocm::array b = {1, 2, 4}; + EXPECT(a < b); + EXPECT(not(b < a)); + EXPECT(not(a < a)); +} + +TEST_CASE(greater_than) +{ + rocm::array a = {1, 2, 4}; + rocm::array b = {1, 2, 3}; + EXPECT(a > b); + EXPECT(not(b > a)); +} + +TEST_CASE(less_equal) +{ + rocm::array a = {1, 2, 3}; + rocm::array b = {1, 2, 4}; + rocm::array c = {1, 2, 3}; + EXPECT(a <= b); + EXPECT(a <= c); + EXPECT(not(b <= a)); +} + +TEST_CASE(greater_equal) +{ + rocm::array a = {1, 2, 4}; + rocm::array b = {1, 2, 3}; + rocm::array c = {1, 2, 4}; + EXPECT(a >= b); + EXPECT(a >= c); + EXPECT(not(b >= a)); +} + +TEST_CASE(less_first_element) +{ + rocm::array a = {0, 9, 9}; + rocm::array b = {1, 0, 0}; + EXPECT(a < b); +} + +// ---- to_array ---- + +TEST_CASE(to_array_lvalue) +{ + int c_arr[] = {10, 20, 30}; + auto a = rocm::to_array(c_arr); + EXPECT(a.size() == 3); + EXPECT(a[0] == 10); + EXPECT(a[1] == 20); + EXPECT(a[2] == 30); +} + +TEST_CASE(to_array_const) +{ + const int c_arr[] = {5, 6}; + auto a = rocm::to_array(c_arr); + EXPECT(a.size() == 2); + EXPECT(a[0] == 5); + EXPECT(a[1] == 6); +} + +// ---- constexpr evaluation ---- + +TEST_CASE(constexpr_size) +{ + static_assert(rocm::array{}.size() == 5); + static_assert(rocm::array{}.size() == 0); +} + +TEST_CASE(constexpr_empty) +{ + static_assert(not rocm::array{}.empty()); + static_assert(rocm::array{}.empty()); +} + +TEST_CASE(constexpr_element_access) +{ + static constexpr rocm::array a = {10, 20, 30}; + static_assert(a[0] == 10); + static_assert(a[1] == 20); + static_assert(a[2] == 30); + static_assert(a.front() == 10); + static_assert(a.back() == 30); + static_assert(a.at(1) == 20); +} + +TEST_CASE(constexpr_comparison) +{ + static constexpr rocm::array a = {1, 2, 3}; + static constexpr rocm::array b = {1, 2, 3}; + static constexpr rocm::array c = {1, 2, 4}; + static_assert(a == b); + static_assert(a != c); + static_assert(a < c); + static_assert(c > a); + static_assert(a <= b); + static_assert(a >= b); +} + +TEST_CASE(constexpr_iterator) +{ + static constexpr rocm::array a = {10, 20, 30}; + static_assert(*a.begin() == 10); + static_assert(*(a.end() - 1) == 30); + static_assert(a.end() - a.begin() == 3); +} + +TEST_CASE(constexpr_reverse_iterator) +{ + static constexpr rocm::array a = {10, 20, 30}; + static_assert(*a.rbegin() == 30); + static_assert(*(a.rend() - 1) == 10); +} + +// ---- type aliases ---- + +TEST_CASE(type_aliases) +{ + EXPECT(rocm::is_same::value_type, int>{}); + EXPECT(rocm::is_same::pointer, int*>{}); + EXPECT(rocm::is_same::const_pointer, const int*>{}); + EXPECT(rocm::is_same::reference, int&>{}); + EXPECT(rocm::is_same::const_reference, const int&>{}); + EXPECT(rocm::is_same::size_type, rocm::size_t>{}); + EXPECT(rocm::is_same::difference_type, rocm::ptrdiff_t>{}); +} + +// ---- iterate and sum ---- + +TEST_CASE(iterate_forward) +{ + rocm::array a = {1, 2, 3, 4, 5}; + int sum = 0; + // The raw loop deliberately exercises array iteration, which is what this test covers. + for(const int& it : a) + { + // cppcheck-suppress useStlAlgorithm + sum += it; + } + EXPECT(sum == 15); +} + +TEST_CASE(iterate_reverse) +{ + rocm::array a = {10, 20, 30, 40}; + int result = 0; + int factor = 1; + for(auto it = a.rbegin(); it != a.rend(); ++it) + { + result += *it * factor; + factor *= 10; + } + // 40*1 + 30*10 + 20*100 + 10*1000 = 40 + 300 + 2000 + 10000 = 12340 + EXPECT(result == 12340); +} + +// ---- different element types ---- + +TEST_CASE(char_array) +{ + rocm::array a = {'a', 'b', 'c'}; + EXPECT(a[0] == 'a'); + EXPECT(a[2] == 'c'); + EXPECT(a.size() == 3); +} + +TEST_CASE(long_array) +{ + rocm::array a = {100000L, 200000L}; + EXPECT(a.front() == 100000L); + EXPECT(a.back() == 200000L); +} diff --git a/test/gpu/kernels/rocm/bit.cpp b/test/gpu/kernels/rocm/bit.cpp new file mode 100644 index 00000000000..f0d324e27cc --- /dev/null +++ b/test/gpu/kernels/rocm/bit.cpp @@ -0,0 +1,893 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2025-2026 Advanced Micro Devices, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#include +#include + +// SFINAE detection: checks whether rocm::bit_cast(From{}) is well-formed +template +struct can_bit_cast : rocm::false_type +{ +}; + +template +struct can_bit_cast(From{}))>> : rocm::true_type +{ +}; + +// Trivially copyable POD structs (4 bytes each) +struct pod_a +{ + int x; +}; + +struct pod_b +{ + unsigned int y; +}; + +// Non-trivially copyable type (user-defined copy constructor) +struct non_trivial +{ + int x; + constexpr non_trivial() : x(0) {} + constexpr non_trivial(const non_trivial& other) : x(other.x) {} +}; + +// 8-byte non-trivially copyable type +struct non_trivial_8 +{ + double d; + constexpr non_trivial_8() : d(0.0) {} + constexpr non_trivial_8(const non_trivial_8& other) : d(other.d) {} +}; + +// Trivially copyable but NOT trivially constructible +// (user-defined default ctor; copy/move/dtor are implicitly trivial) +struct trivial_copy_nontrivial_ctor +{ + int x; + constexpr trivial_copy_nontrivial_ctor() : x(42) {} +}; + +// Enum type (trivially copyable, same size as underlying type) +enum class color : int +{ + red = 0, + green = 1, + blue = 2 +}; + +// ---- Verify test type sizes ---- +static_assert(sizeof(pod_a) == sizeof(int)); +static_assert(sizeof(pod_b) == sizeof(unsigned int)); +static_assert(sizeof(non_trivial) == sizeof(int)); +static_assert(sizeof(non_trivial_8) == sizeof(double)); +static_assert(sizeof(trivial_copy_nontrivial_ctor) == sizeof(int)); +static_assert(sizeof(color) == sizeof(int)); +static_assert(sizeof(double) == sizeof(unsigned long long)); + +// Verify trivial_copy_nontrivial_ctor properties +static_assert(rocm::is_trivially_copyable{}); +static_assert(not rocm::is_trivially_constructible{}); + +// ---- SFINAE: valid same-size trivially-copyable pairs ---- +// Same type +static_assert(can_bit_cast{}); +static_assert(can_bit_cast{}); +static_assert(can_bit_cast{}); +static_assert(can_bit_cast{}); +static_assert(can_bit_cast{}); + +// Same-size different types +static_assert(can_bit_cast{}); +static_assert(can_bit_cast{}); +static_assert(can_bit_cast{}); +static_assert(can_bit_cast{}); +static_assert(can_bit_cast{}); +static_assert(can_bit_cast{}); +static_assert(can_bit_cast{}); +static_assert(can_bit_cast{}); + +// POD struct pairs +static_assert(can_bit_cast{}); +static_assert(can_bit_cast{}); +static_assert(can_bit_cast{}); +static_assert(can_bit_cast{}); +static_assert(can_bit_cast{}); +static_assert(can_bit_cast{}); + +// Enum types +static_assert(can_bit_cast{}); +static_assert(can_bit_cast{}); +static_assert(can_bit_cast{}); +static_assert(can_bit_cast{}); +static_assert(can_bit_cast{}); +static_assert(can_bit_cast{}); + +// Trivially copyable but not trivially constructible (accepted) +static_assert(can_bit_cast{}); +static_assert(can_bit_cast{}); +static_assert(can_bit_cast{}); +static_assert(can_bit_cast{}); +static_assert(can_bit_cast{}); +static_assert(can_bit_cast{}); +static_assert(can_bit_cast{}); +static_assert(can_bit_cast{}); + +// ---- SFINAE: sizeof mismatch (rejected) ---- +static_assert(not can_bit_cast{}); +static_assert(not can_bit_cast{}); +static_assert(not can_bit_cast{}); +static_assert(not can_bit_cast{}); +static_assert(not can_bit_cast{}); +static_assert(not can_bit_cast{}); +static_assert(not can_bit_cast{}); +static_assert(not can_bit_cast{}); +static_assert(not can_bit_cast{}); +static_assert(not can_bit_cast{}); +static_assert(not can_bit_cast{}); +static_assert(not can_bit_cast{}); +static_assert(not can_bit_cast{}); +static_assert(not can_bit_cast{}); + +// ---- SFINAE: non-trivially-copyable (rejected) ---- +// Same size but not trivially copyable +static_assert(not can_bit_cast{}); +static_assert(not can_bit_cast{}); +static_assert(not can_bit_cast{}); +static_assert(not can_bit_cast{}); +static_assert(not can_bit_cast{}); +static_assert(not can_bit_cast{}); +static_assert(not can_bit_cast{}); +// Different size AND not trivially copyable +static_assert(not can_bit_cast{}); +static_assert(not can_bit_cast{}); +static_assert(not can_bit_cast{}); +static_assert(not can_bit_cast{}); +// Same size non-trivially-copyable pair +static_assert(not can_bit_cast{}); +static_assert(not can_bit_cast{}); + +// ---- Constexpr value correctness ---- +// Identity +static_assert(rocm::bit_cast(0) == 0); +static_assert(rocm::bit_cast(42) == 42); +static_assert(rocm::bit_cast(-1) == -1); + +// int <-> unsigned int +static_assert(rocm::bit_cast(0) == 0u); +static_assert(rocm::bit_cast(0u) == 0); +static_assert(rocm::bit_cast(-1) == ~0u); + +// float <-> unsigned int (IEEE 754 single-precision) +static_assert(rocm::bit_cast(0.0f) == 0x00000000u); +static_assert(rocm::bit_cast(1.0f) == 0x3F800000u); +static_assert(rocm::bit_cast(-1.0f) == 0xBF800000u); +static_assert(rocm::bit_cast(0.5f) == 0x3F000000u); +static_assert(rocm::bit_cast(2.0f) == 0x40000000u); +static_assert(rocm::bit_cast(0x3F800000u) == 1.0f); +static_assert(rocm::bit_cast(0x00000000u) == 0.0f); + +// Constexpr roundtrip +static_assert(rocm::bit_cast(rocm::bit_cast(1.0f)) == 1.0f); +static_assert(rocm::bit_cast(rocm::bit_cast(42)) == 42); +static_assert(rocm::bit_cast(rocm::bit_cast(123u)) == 123u); + +TEST_CASE(bit_cast_identity) +{ + EXPECT(rocm::bit_cast(0) == 0); + EXPECT(rocm::bit_cast(42) == 42); + EXPECT(rocm::bit_cast(-1) == -1); + EXPECT(rocm::bit_cast(0u) == 0u); + EXPECT(rocm::bit_cast(123u) == 123u); + EXPECT(rocm::bit_cast('A') == 'A'); + + // Float/double identity verified via integer bit patterns + EXPECT(rocm::bit_cast(rocm::bit_cast(1.0f)) == 0x3F800000u); + EXPECT(rocm::bit_cast(rocm::bit_cast(0.0f)) == 0x00000000u); + EXPECT(rocm::bit_cast(rocm::bit_cast(1.0)) == + 0x3FF0000000000000ull); +} + +TEST_CASE(bit_cast_int_unsigned) +{ + EXPECT(rocm::bit_cast(0) == 0u); + EXPECT(rocm::bit_cast(1) == 1u); + EXPECT(rocm::bit_cast(-1) == ~0u); + EXPECT(rocm::bit_cast(0u) == 0); + EXPECT(rocm::bit_cast(1u) == 1); + + EXPECT(rocm::bit_cast(static_cast(0)) == 0u); + EXPECT(rocm::bit_cast(static_cast(1)) == 1u); + EXPECT(rocm::bit_cast(static_cast(0)) == 0); + EXPECT(rocm::bit_cast(static_cast(1)) == 1); + + EXPECT(rocm::bit_cast(static_cast(0)) == 0); + EXPECT(rocm::bit_cast(static_cast(65)) == 'A'); +} + +TEST_CASE(bit_cast_float_to_int) +{ + // IEEE 754 single-precision bit patterns + EXPECT(rocm::bit_cast(0.0f) == 0x00000000u); + EXPECT(rocm::bit_cast(1.0f) == 0x3F800000u); + EXPECT(rocm::bit_cast(-1.0f) == 0xBF800000u); + EXPECT(rocm::bit_cast(0.5f) == 0x3F000000u); + EXPECT(rocm::bit_cast(2.0f) == 0x40000000u); + EXPECT(rocm::bit_cast(-0.0f) == 0x80000000u); +} + +TEST_CASE(bit_cast_int_to_float) +{ + // Verify uint -> float -> uint preserves all bits + EXPECT(rocm::bit_cast(rocm::bit_cast(0x3F800000u)) == 0x3F800000u); + EXPECT(rocm::bit_cast(rocm::bit_cast(0x00000000u)) == 0x00000000u); + EXPECT(rocm::bit_cast(rocm::bit_cast(0x40000000u)) == 0x40000000u); + EXPECT(rocm::bit_cast(rocm::bit_cast(0x3F000000u)) == 0x3F000000u); + EXPECT(rocm::bit_cast(rocm::bit_cast(0xBF800000u)) == 0xBF800000u); + EXPECT(rocm::bit_cast(rocm::bit_cast(0x80000000u)) == 0x80000000u); +} + +TEST_CASE(bit_cast_roundtrip) +{ + // float -> unsigned int -> float (verified via bit pattern) + EXPECT(rocm::bit_cast( + rocm::bit_cast(rocm::bit_cast(1.0f))) == 0x3F800000u); + EXPECT(rocm::bit_cast( + rocm::bit_cast(rocm::bit_cast(0.0f))) == 0x00000000u); + EXPECT(rocm::bit_cast( + rocm::bit_cast(rocm::bit_cast(-1.0f))) == 0xBF800000u); + EXPECT(rocm::bit_cast(rocm::bit_cast( + rocm::bit_cast(3.14f))) == rocm::bit_cast(3.14f)); + + // int -> unsigned int -> int + EXPECT(rocm::bit_cast(rocm::bit_cast(0)) == 0); + EXPECT(rocm::bit_cast(rocm::bit_cast(42)) == 42); + EXPECT(rocm::bit_cast(rocm::bit_cast(-42)) == -42); + + // unsigned int -> int -> unsigned int + EXPECT(rocm::bit_cast(rocm::bit_cast(0u)) == 0u); + EXPECT(rocm::bit_cast(rocm::bit_cast(100u)) == 100u); +} + +TEST_CASE(bit_cast_pod_struct) +{ + pod_a a{42}; + pod_b b = rocm::bit_cast(a); + EXPECT(b.y == 42u); + + pod_b b2{100u}; + pod_a a2 = rocm::bit_cast(b2); + EXPECT(a2.x == 100); + + // Roundtrip through pod structs + pod_a a3{-1}; + pod_a a4 = rocm::bit_cast(rocm::bit_cast(a3)); + EXPECT(a4.x == -1); +} + +TEST_CASE(bit_cast_enum) +{ + EXPECT(rocm::bit_cast(color::red) == 0); + EXPECT(rocm::bit_cast(color::green) == 1); + EXPECT(rocm::bit_cast(color::blue) == 2); + + EXPECT(rocm::bit_cast(0) == color::red); + EXPECT(rocm::bit_cast(1) == color::green); + EXPECT(rocm::bit_cast(2) == color::blue); +} + +TEST_CASE(bit_cast_trivial_copy_nontrivial_ctor) +{ + // Trivially copyable but not trivially constructible: bit_cast should still work + trivial_copy_nontrivial_ctor tc; + EXPECT(tc.x == 42); + + // To int and back + int i = rocm::bit_cast(tc); + EXPECT(i == 42); + + trivial_copy_nontrivial_ctor tc2 = rocm::bit_cast(99); + EXPECT(tc2.x == 99); + + // Roundtrip + trivial_copy_nontrivial_ctor tc3 = + rocm::bit_cast(rocm::bit_cast(tc)); + EXPECT(tc3.x == 42); + + // To/from float (same size, both trivially copyable) + unsigned int bits = rocm::bit_cast(rocm::bit_cast(tc)); + EXPECT(bits == rocm::bit_cast(tc)); + + // To/from pod struct + pod_a pa = rocm::bit_cast(tc); + EXPECT(pa.x == 42); + + trivial_copy_nontrivial_ctor tc4 = rocm::bit_cast(pod_b{7u}); + EXPECT(tc4.x == 7); +} + +// ============================================================================ +// SFINAE detection for unsigned-only bit functions +// ============================================================================ + +template +struct can_popcount : rocm::false_type +{ +}; + +template +struct can_popcount> : rocm::true_type +{ +}; + +template +struct can_countl_zero : rocm::false_type +{ +}; + +template +struct can_countl_zero> : rocm::true_type +{ +}; + +template +struct can_rotl : rocm::false_type +{ +}; + +template +struct can_rotl> : rocm::true_type +{ +}; + +// Unsigned types accepted +static_assert(can_popcount{}); +static_assert(can_popcount{}); +static_assert(can_popcount{}); +static_assert(can_popcount{}); +static_assert(can_countl_zero{}); +static_assert(can_countl_zero{}); +static_assert(can_countl_zero{}); +static_assert(can_countl_zero{}); +static_assert(can_rotl{}); +static_assert(can_rotl{}); +static_assert(can_rotl{}); +static_assert(can_rotl{}); + +// Signed and non-integer types rejected +static_assert(not can_popcount{}); +static_assert(not can_popcount{}); +static_assert(not can_popcount{}); +static_assert(not can_popcount{}); +static_assert(not can_popcount{}); +static_assert(not can_popcount{}); +static_assert(not can_countl_zero{}); +static_assert(not can_countl_zero{}); +static_assert(not can_rotl{}); +static_assert(not can_rotl{}); + +// ============================================================================ +// Constexpr correctness: countl_zero +// ============================================================================ +// unsigned int (32-bit) +static_assert(rocm::countl_zero(0u) == 32); +static_assert(rocm::countl_zero(1u) == 31); +static_assert(rocm::countl_zero(2u) == 30); +static_assert(rocm::countl_zero(0x80000000u) == 0); +static_assert(rocm::countl_zero(0xFFFFFFFFu) == 0); +static_assert(rocm::countl_zero(0x0000FFFFu) == 16); +static_assert(rocm::countl_zero(0x00010000u) == 15); +// unsigned char (8-bit) +static_assert(rocm::countl_zero(static_cast(0)) == 8); +static_assert(rocm::countl_zero(static_cast(1)) == 7); +static_assert(rocm::countl_zero(static_cast(0x80)) == 0); +static_assert(rocm::countl_zero(static_cast(0xFF)) == 0); +// unsigned long long (64-bit) +static_assert(rocm::countl_zero(0ull) == 64); +static_assert(rocm::countl_zero(1ull) == 63); +static_assert(rocm::countl_zero(0x8000000000000000ull) == 0); + +// ============================================================================ +// Constexpr correctness: countl_one +// ============================================================================ +static_assert(rocm::countl_one(0u) == 0); +static_assert(rocm::countl_one(0xFFFFFFFFu) == 32); +static_assert(rocm::countl_one(0x80000000u) == 1); +static_assert(rocm::countl_one(0xF0000000u) == 4); +static_assert(rocm::countl_one(0xFFF00000u) == 12); +// unsigned char (8-bit) +static_assert(rocm::countl_one(static_cast(0xFF)) == 8); +static_assert(rocm::countl_one(static_cast(0xF0)) == 4); +static_assert(rocm::countl_one(static_cast(0x00)) == 0); + +// ============================================================================ +// Constexpr correctness: countr_zero +// ============================================================================ +static_assert(rocm::countr_zero(0u) == 32); +static_assert(rocm::countr_zero(1u) == 0); +static_assert(rocm::countr_zero(2u) == 1); +static_assert(rocm::countr_zero(0x80000000u) == 31); +static_assert(rocm::countr_zero(0x00010000u) == 16); +static_assert(rocm::countr_zero(0xFFFFFFFFu) == 0); +static_assert(rocm::countr_zero(static_cast(0)) == 8); +static_assert(rocm::countr_zero(static_cast(0x80)) == 7); + +// ============================================================================ +// Constexpr correctness: countr_one +// ============================================================================ +static_assert(rocm::countr_one(0u) == 0); +static_assert(rocm::countr_one(1u) == 1); +static_assert(rocm::countr_one(0xFFFFFFFFu) == 32); +static_assert(rocm::countr_one(0x0000000Fu) == 4); +static_assert(rocm::countr_one(0x000000FFu) == 8); +// unsigned char (8-bit) +static_assert(rocm::countr_one(static_cast(0xFF)) == 8); +static_assert(rocm::countr_one(static_cast(0x0F)) == 4); +static_assert(rocm::countr_one(static_cast(0x00)) == 0); + +// ============================================================================ +// Constexpr correctness: popcount +// ============================================================================ +static_assert(rocm::popcount(0u) == 0); +static_assert(rocm::popcount(1u) == 1); +static_assert(rocm::popcount(0xFFFFFFFFu) == 32); +static_assert(rocm::popcount(0x55555555u) == 16); +static_assert(rocm::popcount(0xAAAAAAAAu) == 16); +static_assert(rocm::popcount(0x000000FFu) == 8); +static_assert(rocm::popcount(0x0F0F0F0Fu) == 16); +static_assert(rocm::popcount(static_cast(0)) == 0); +static_assert(rocm::popcount(static_cast(0xFF)) == 8); +static_assert(rocm::popcount(static_cast(0xAA)) == 4); +static_assert(rocm::popcount(0xFFFFFFFFFFFFFFFFull) == 64); + +// ============================================================================ +// Constexpr correctness: bit_width +// ============================================================================ +static_assert(rocm::bit_width(0u) == 0); +static_assert(rocm::bit_width(1u) == 1); +static_assert(rocm::bit_width(2u) == 2); +static_assert(rocm::bit_width(3u) == 2); +static_assert(rocm::bit_width(4u) == 3); +static_assert(rocm::bit_width(7u) == 3); +static_assert(rocm::bit_width(8u) == 4); +static_assert(rocm::bit_width(255u) == 8); +static_assert(rocm::bit_width(256u) == 9); +static_assert(rocm::bit_width(0xFFFFFFFFu) == 32); +static_assert(rocm::bit_width(static_cast(0)) == 0); +static_assert(rocm::bit_width(static_cast(0xFF)) == 8); + +// ============================================================================ +// Constexpr correctness: bit_floor +// ============================================================================ +static_assert(rocm::bit_floor(0u) == 0u); +static_assert(rocm::bit_floor(1u) == 1u); +static_assert(rocm::bit_floor(2u) == 2u); +static_assert(rocm::bit_floor(3u) == 2u); +static_assert(rocm::bit_floor(4u) == 4u); +static_assert(rocm::bit_floor(5u) == 4u); +static_assert(rocm::bit_floor(7u) == 4u); +static_assert(rocm::bit_floor(8u) == 8u); +static_assert(rocm::bit_floor(9u) == 8u); +static_assert(rocm::bit_floor(255u) == 128u); +static_assert(rocm::bit_floor(0xFFFFFFFFu) == 0x80000000u); + +// ============================================================================ +// Constexpr correctness: bit_ceil +// ============================================================================ +static_assert(rocm::bit_ceil(0u) == 1u); +static_assert(rocm::bit_ceil(1u) == 1u); +static_assert(rocm::bit_ceil(2u) == 2u); +static_assert(rocm::bit_ceil(3u) == 4u); +static_assert(rocm::bit_ceil(4u) == 4u); +static_assert(rocm::bit_ceil(5u) == 8u); +static_assert(rocm::bit_ceil(7u) == 8u); +static_assert(rocm::bit_ceil(8u) == 8u); +static_assert(rocm::bit_ceil(9u) == 16u); +static_assert(rocm::bit_ceil(128u) == 128u); +static_assert(rocm::bit_ceil(129u) == 256u); + +// ============================================================================ +// Constexpr correctness: has_single_bit +// ============================================================================ +static_assert(not rocm::has_single_bit(0u)); +static_assert(rocm::has_single_bit(1u)); +static_assert(rocm::has_single_bit(2u)); +static_assert(not rocm::has_single_bit(3u)); +static_assert(rocm::has_single_bit(4u)); +static_assert(not rocm::has_single_bit(5u)); +static_assert(not rocm::has_single_bit(6u)); +static_assert(not rocm::has_single_bit(7u)); +static_assert(rocm::has_single_bit(8u)); +static_assert(rocm::has_single_bit(0x80000000u)); +static_assert(not rocm::has_single_bit(0xFFFFFFFFu)); + +// ============================================================================ +// Constexpr correctness: rotl +// ============================================================================ +static_assert(rocm::rotl(1u, 0) == 1u); +static_assert(rocm::rotl(1u, 1) == 2u); +static_assert(rocm::rotl(1u, 4) == 16u); +static_assert(rocm::rotl(1u, 31) == 0x80000000u); +static_assert(rocm::rotl(0x80000000u, 1) == 1u); +static_assert(rocm::rotl(0x12345678u, 4) == 0x23456781u); +static_assert(rocm::rotl(0x12345678u, 8) == 0x34567812u); +static_assert(rocm::rotl(1u, 32) == 1u); +static_assert(rocm::rotl(1u, -1) == 0x80000000u); + +// ============================================================================ +// Constexpr correctness: rotr +// ============================================================================ +static_assert(rocm::rotr(1u, 0) == 1u); +static_assert(rocm::rotr(1u, 1) == 0x80000000u); +static_assert(rocm::rotr(0x80000000u, 1) == 0x40000000u); +static_assert(rocm::rotr(0x12345678u, 4) == 0x81234567u); +static_assert(rocm::rotr(0x12345678u, 8) == 0x78123456u); +static_assert(rocm::rotr(1u, 32) == 1u); +static_assert(rocm::rotr(1u, -1) == 2u); + +// rotl/rotr are inverses +static_assert(rocm::rotl(rocm::rotr(0xDEADBEEFu, 7), 7) == 0xDEADBEEFu); +static_assert(rocm::rotr(rocm::rotl(0xDEADBEEFu, 13), 13) == 0xDEADBEEFu); + +// ============================================================================ +// Runtime tests +// ============================================================================ + +TEST_CASE(countl_zero_test) +{ + // unsigned int + EXPECT(rocm::countl_zero(0u) == 32); + EXPECT(rocm::countl_zero(1u) == 31); + EXPECT(rocm::countl_zero(0x80000000u) == 0); + EXPECT(rocm::countl_zero(0xFFFFFFFFu) == 0); + EXPECT(rocm::countl_zero(0x0000FFFFu) == 16); + + // unsigned char + EXPECT(rocm::countl_zero(static_cast(0)) == 8); + EXPECT(rocm::countl_zero(static_cast(1)) == 7); + EXPECT(rocm::countl_zero(static_cast(0x80)) == 0); + EXPECT(rocm::countl_zero(static_cast(0x0F)) == 4); + + // unsigned long long + EXPECT(rocm::countl_zero(0ull) == 64); + EXPECT(rocm::countl_zero(1ull) == 63); + EXPECT(rocm::countl_zero(0x8000000000000000ull) == 0); + EXPECT(rocm::countl_zero(0x00000000FFFFFFFFull) == 32); +} + +TEST_CASE(countl_one_test) +{ + EXPECT(rocm::countl_one(0u) == 0); + EXPECT(rocm::countl_one(0xFFFFFFFFu) == 32); + EXPECT(rocm::countl_one(0x80000000u) == 1); + EXPECT(rocm::countl_one(0xF0000000u) == 4); + EXPECT(rocm::countl_one(0xFFF00000u) == 12); + EXPECT(rocm::countl_one(0xFFFFFFFEu) == 31); + + // unsigned char + EXPECT(rocm::countl_one(static_cast(0xFF)) == 8); + EXPECT(rocm::countl_one(static_cast(0xF0)) == 4); + EXPECT(rocm::countl_one(static_cast(0x00)) == 0); + EXPECT(rocm::countl_one(static_cast(0xFE)) == 7); + + // unsigned long long + EXPECT(rocm::countl_one(0xFFFFFFFFFFFFFFFFull) == 64); + EXPECT(rocm::countl_one(0xFFFFFFFF00000000ull) == 32); +} + +TEST_CASE(countr_zero_test) +{ + EXPECT(rocm::countr_zero(0u) == 32); + EXPECT(rocm::countr_zero(1u) == 0); + EXPECT(rocm::countr_zero(2u) == 1); + EXPECT(rocm::countr_zero(4u) == 2); + EXPECT(rocm::countr_zero(0x80000000u) == 31); + EXPECT(rocm::countr_zero(0x00010000u) == 16); + EXPECT(rocm::countr_zero(0xFFFFFFFFu) == 0); + EXPECT(rocm::countr_zero(0xFFFF0000u) == 16); + + // unsigned char + EXPECT(rocm::countr_zero(static_cast(0)) == 8); + EXPECT(rocm::countr_zero(static_cast(1)) == 0); + EXPECT(rocm::countr_zero(static_cast(0x80)) == 7); + EXPECT(rocm::countr_zero(static_cast(0x10)) == 4); + + // unsigned long long + EXPECT(rocm::countr_zero(0ull) == 64); + EXPECT(rocm::countr_zero(0x0000000100000000ull) == 32); +} + +TEST_CASE(countr_one_test) +{ + EXPECT(rocm::countr_one(0u) == 0); + EXPECT(rocm::countr_one(1u) == 1); + EXPECT(rocm::countr_one(3u) == 2); + EXPECT(rocm::countr_one(0x0000000Fu) == 4); + EXPECT(rocm::countr_one(0x000000FFu) == 8); + EXPECT(rocm::countr_one(0xFFFFFFFFu) == 32); + EXPECT(rocm::countr_one(0x0000FFFEu) == 0); + + // unsigned char + EXPECT(rocm::countr_one(static_cast(0xFF)) == 8); + EXPECT(rocm::countr_one(static_cast(0x0F)) == 4); + EXPECT(rocm::countr_one(static_cast(0x00)) == 0); + EXPECT(rocm::countr_one(static_cast(0x7F)) == 7); + + // unsigned long long + EXPECT(rocm::countr_one(0xFFFFFFFFFFFFFFFFull) == 64); + EXPECT(rocm::countr_one(0x00000000FFFFFFFFull) == 32); +} + +TEST_CASE(popcount_test) +{ + EXPECT(rocm::popcount(0u) == 0); + EXPECT(rocm::popcount(1u) == 1); + EXPECT(rocm::popcount(0xFFFFFFFFu) == 32); + EXPECT(rocm::popcount(0x55555555u) == 16); + EXPECT(rocm::popcount(0xAAAAAAAAu) == 16); + EXPECT(rocm::popcount(0x000000FFu) == 8); + EXPECT(rocm::popcount(0x0F0F0F0Fu) == 16); + EXPECT(rocm::popcount(0x80000001u) == 2); + + // unsigned char + EXPECT(rocm::popcount(static_cast(0)) == 0); + EXPECT(rocm::popcount(static_cast(0xFF)) == 8); + EXPECT(rocm::popcount(static_cast(0xAA)) == 4); + EXPECT(rocm::popcount(static_cast(0x55)) == 4); + + // unsigned long long + EXPECT(rocm::popcount(0ull) == 0); + EXPECT(rocm::popcount(0xFFFFFFFFFFFFFFFFull) == 64); + EXPECT(rocm::popcount(0x5555555555555555ull) == 32); +} + +TEST_CASE(bit_width_test) +{ + EXPECT(rocm::bit_width(0u) == 0); + EXPECT(rocm::bit_width(1u) == 1); + EXPECT(rocm::bit_width(2u) == 2); + EXPECT(rocm::bit_width(3u) == 2); + EXPECT(rocm::bit_width(4u) == 3); + EXPECT(rocm::bit_width(7u) == 3); + EXPECT(rocm::bit_width(8u) == 4); + EXPECT(rocm::bit_width(15u) == 4); + EXPECT(rocm::bit_width(16u) == 5); + EXPECT(rocm::bit_width(255u) == 8); + EXPECT(rocm::bit_width(256u) == 9); + EXPECT(rocm::bit_width(0xFFFFFFFFu) == 32); + + // unsigned char + EXPECT(rocm::bit_width(static_cast(0)) == 0); + EXPECT(rocm::bit_width(static_cast(1)) == 1); + EXPECT(rocm::bit_width(static_cast(0xFF)) == 8); + EXPECT(rocm::bit_width(static_cast(0x80)) == 8); + + // unsigned long long + EXPECT(rocm::bit_width(0ull) == 0); + EXPECT(rocm::bit_width(1ull) == 1); + EXPECT(rocm::bit_width(0xFFFFFFFFFFFFFFFFull) == 64); +} + +TEST_CASE(bit_floor_test) +{ + EXPECT(rocm::bit_floor(0u) == 0u); + EXPECT(rocm::bit_floor(1u) == 1u); + EXPECT(rocm::bit_floor(2u) == 2u); + EXPECT(rocm::bit_floor(3u) == 2u); + EXPECT(rocm::bit_floor(4u) == 4u); + EXPECT(rocm::bit_floor(5u) == 4u); + EXPECT(rocm::bit_floor(7u) == 4u); + EXPECT(rocm::bit_floor(8u) == 8u); + EXPECT(rocm::bit_floor(9u) == 8u); + EXPECT(rocm::bit_floor(255u) == 128u); + EXPECT(rocm::bit_floor(256u) == 256u); + EXPECT(rocm::bit_floor(0xFFFFFFFFu) == 0x80000000u); + + // unsigned char + EXPECT(rocm::bit_floor(static_cast(0)) == 0); + EXPECT(rocm::bit_floor(static_cast(1)) == 1); + EXPECT(rocm::bit_floor(static_cast(3)) == 2); + EXPECT(rocm::bit_floor(static_cast(0xFF)) == 0x80); + + // unsigned long long + EXPECT(rocm::bit_floor(0ull) == 0ull); + EXPECT(rocm::bit_floor(1ull) == 1ull); + EXPECT(rocm::bit_floor(0xFFFFFFFFFFFFFFFFull) == 0x8000000000000000ull); +} + +TEST_CASE(bit_ceil_test) +{ + EXPECT(rocm::bit_ceil(0u) == 1u); + EXPECT(rocm::bit_ceil(1u) == 1u); + EXPECT(rocm::bit_ceil(2u) == 2u); + EXPECT(rocm::bit_ceil(3u) == 4u); + EXPECT(rocm::bit_ceil(4u) == 4u); + EXPECT(rocm::bit_ceil(5u) == 8u); + EXPECT(rocm::bit_ceil(7u) == 8u); + EXPECT(rocm::bit_ceil(8u) == 8u); + EXPECT(rocm::bit_ceil(9u) == 16u); + EXPECT(rocm::bit_ceil(128u) == 128u); + EXPECT(rocm::bit_ceil(129u) == 256u); + EXPECT(rocm::bit_ceil(0x40000000u) == 0x40000000u); + + // unsigned char (max safe value is 128, since 129 would need 256 which overflows) + EXPECT(rocm::bit_ceil(static_cast(0)) == 1); + EXPECT(rocm::bit_ceil(static_cast(1)) == 1); + EXPECT(rocm::bit_ceil(static_cast(3)) == 4); + EXPECT(rocm::bit_ceil(static_cast(64)) == 64); + EXPECT(rocm::bit_ceil(static_cast(128)) == 128); + + // unsigned long long + EXPECT(rocm::bit_ceil(0ull) == 1ull); + EXPECT(rocm::bit_ceil(1ull) == 1ull); + EXPECT(rocm::bit_ceil(3ull) == 4ull); + EXPECT(rocm::bit_ceil(0x100ull) == 0x100ull); + EXPECT(rocm::bit_ceil(0x101ull) == 0x200ull); +} + +TEST_CASE(has_single_bit_test) +{ + EXPECT(not rocm::has_single_bit(0u)); + EXPECT(rocm::has_single_bit(1u)); + EXPECT(rocm::has_single_bit(2u)); + EXPECT(not rocm::has_single_bit(3u)); + EXPECT(rocm::has_single_bit(4u)); + EXPECT(not rocm::has_single_bit(5u)); + EXPECT(not rocm::has_single_bit(6u)); + EXPECT(not rocm::has_single_bit(7u)); + EXPECT(rocm::has_single_bit(8u)); + EXPECT(rocm::has_single_bit(16u)); + EXPECT(rocm::has_single_bit(0x80000000u)); + EXPECT(not rocm::has_single_bit(0xFFFFFFFFu)); + EXPECT(not rocm::has_single_bit(0x80000001u)); + + // unsigned char + EXPECT(not rocm::has_single_bit(static_cast(0))); + EXPECT(rocm::has_single_bit(static_cast(1))); + EXPECT(rocm::has_single_bit(static_cast(0x80))); + EXPECT(not rocm::has_single_bit(static_cast(0xFF))); + + // unsigned long long + EXPECT(rocm::has_single_bit(1ull)); + EXPECT(rocm::has_single_bit(0x8000000000000000ull)); + EXPECT(not rocm::has_single_bit(0xFFFFFFFFFFFFFFFFull)); +} + +TEST_CASE(rotl_test) +{ + // Zero rotation + EXPECT(rocm::rotl(0xABCDEF01u, 0) == 0xABCDEF01u); + + // Basic rotations + EXPECT(rocm::rotl(1u, 1) == 2u); + EXPECT(rocm::rotl(1u, 4) == 16u); + EXPECT(rocm::rotl(1u, 31) == 0x80000000u); + EXPECT(rocm::rotl(0x80000000u, 1) == 1u); + + // Multi-nibble rotations + EXPECT(rocm::rotl(0x12345678u, 4) == 0x23456781u); + EXPECT(rocm::rotl(0x12345678u, 8) == 0x34567812u); + EXPECT(rocm::rotl(0x12345678u, 16) == 0x56781234u); + EXPECT(rocm::rotl(0x12345678u, 24) == 0x78123456u); + + // Full rotation (identity) + EXPECT(rocm::rotl(0xDEADBEEFu, 32) == 0xDEADBEEFu); + + // Negative rotation (equivalent to rotr) + EXPECT(rocm::rotl(1u, -1) == 0x80000000u); + EXPECT(rocm::rotl(0x12345678u, -4) == 0x81234567u); + + // unsigned char (8-bit) + EXPECT(rocm::rotl(static_cast(1), 1) == 2); + EXPECT(rocm::rotl(static_cast(0x80), 1) == 1); + EXPECT(rocm::rotl(static_cast(0x0F), 4) == 0xF0); + + // unsigned long long (64-bit) + EXPECT(rocm::rotl(1ull, 63) == 0x8000000000000000ull); + EXPECT(rocm::rotl(0x8000000000000000ull, 1) == 1ull); +} + +TEST_CASE(rotr_test) +{ + // Zero rotation + EXPECT(rocm::rotr(0xABCDEF01u, 0) == 0xABCDEF01u); + + // Basic rotations + EXPECT(rocm::rotr(1u, 1) == 0x80000000u); + EXPECT(rocm::rotr(2u, 1) == 1u); + EXPECT(rocm::rotr(0x80000000u, 1) == 0x40000000u); + + // Multi-nibble rotations + EXPECT(rocm::rotr(0x12345678u, 4) == 0x81234567u); + EXPECT(rocm::rotr(0x12345678u, 8) == 0x78123456u); + EXPECT(rocm::rotr(0x12345678u, 16) == 0x56781234u); + EXPECT(rocm::rotr(0x12345678u, 24) == 0x34567812u); + + // Full rotation (identity) + EXPECT(rocm::rotr(0xDEADBEEFu, 32) == 0xDEADBEEFu); + + // Negative rotation (equivalent to rotl) + EXPECT(rocm::rotr(1u, -1) == 2u); + EXPECT(rocm::rotr(0x12345678u, -4) == 0x23456781u); + + // unsigned char (8-bit) + EXPECT(rocm::rotr(static_cast(1), 1) == 0x80); + EXPECT(rocm::rotr(static_cast(0x80), 1) == 0x40); + EXPECT(rocm::rotr(static_cast(0xF0), 4) == 0x0F); + + // unsigned long long (64-bit) + EXPECT(rocm::rotr(1ull, 1) == 0x8000000000000000ull); + EXPECT(rocm::rotr(0x8000000000000000ull, 63) == 1ull); +} + +TEST_CASE(rotl_rotr_inverse) +{ + // rotl(rotr(x, s), s) == x + EXPECT(rocm::rotl(rocm::rotr(0xDEADBEEFu, 1), 1) == 0xDEADBEEFu); + EXPECT(rocm::rotl(rocm::rotr(0xDEADBEEFu, 7), 7) == 0xDEADBEEFu); + EXPECT(rocm::rotl(rocm::rotr(0xDEADBEEFu, 13), 13) == 0xDEADBEEFu); + EXPECT(rocm::rotl(rocm::rotr(0xDEADBEEFu, 31), 31) == 0xDEADBEEFu); + + // rotr(rotl(x, s), s) == x + EXPECT(rocm::rotr(rocm::rotl(0xCAFEBABEu, 1), 1) == 0xCAFEBABEu); + EXPECT(rocm::rotr(rocm::rotl(0xCAFEBABEu, 7), 7) == 0xCAFEBABEu); + EXPECT(rocm::rotr(rocm::rotl(0xCAFEBABEu, 13), 13) == 0xCAFEBABEu); + EXPECT(rocm::rotr(rocm::rotl(0xCAFEBABEu, 31), 31) == 0xCAFEBABEu); + + // rotl(x, s) == rotr(x, -s) + EXPECT(rocm::rotl(0x12345678u, 5) == rocm::rotr(0x12345678u, -5)); + EXPECT(rocm::rotl(0x12345678u, 17) == rocm::rotr(0x12345678u, -17)); +} + +TEST_CASE(count_relationships) +{ + // countl_zero(x) + countl_one(~x) covers all digits (complement relationship) + // popcount(x) + popcount(~x) == digits + EXPECT(rocm::popcount(0x12345678u) + rocm::popcount(~0x12345678u) == 32); + EXPECT(rocm::popcount(0xDEADBEEFu) + rocm::popcount(~0xDEADBEEFu) == 32); + + // countl_zero(x) == countl_one(~x) + EXPECT(rocm::countl_zero(0x12345678u) == rocm::countl_one(~0x12345678u)); + EXPECT(rocm::countr_zero(0x12345678u) == rocm::countr_one(~0x12345678u)); + + // bit_width(x) == digits - countl_zero(x) + EXPECT(rocm::bit_width(0x12345678u) == 32 - rocm::countl_zero(0x12345678u)); + EXPECT(rocm::bit_width(42u) == 32 - rocm::countl_zero(42u)); + + // has_single_bit(x) iff popcount(x) == 1 + EXPECT(rocm::has_single_bit(64u) == (rocm::popcount(64u) == 1)); + EXPECT(rocm::has_single_bit(65u) == (rocm::popcount(65u) == 1)); + + // For powers of 2: bit_floor == bit_ceil == x + EXPECT(rocm::bit_floor(64u) == 64u); + EXPECT(rocm::bit_ceil(64u) == 64u); + + // bit_floor(x) <= x <= bit_ceil(x) for non-zero x + EXPECT(rocm::bit_floor(100u) <= 100u); + EXPECT(100u <= rocm::bit_ceil(100u)); + EXPECT(rocm::bit_floor(100u) == 64u); + EXPECT(rocm::bit_ceil(100u) == 128u); +} diff --git a/test/gpu/kernels/rocm/enable_if.cpp b/test/gpu/kernels/rocm/enable_if.cpp new file mode 100644 index 00000000000..c4a7e9012e1 --- /dev/null +++ b/test/gpu/kernels/rocm/enable_if.cpp @@ -0,0 +1,101 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2025-2026 Advanced Micro Devices, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#include +#include + +template +struct check : rocm::bool_constant +{ +}; + +template <> +struct check : rocm::bool_constant +{ +}; + +struct construct +{ + template + constexpr construct(T, typename rocm::enable_if{}>::type* = nullptr) : v(true) + { + } + template + constexpr construct(T, typename rocm::enable_if{}>::type* = nullptr) : v(false) + { + } + constexpr bool value() const { return v; } + + private: + bool v; +}; + +template +struct specialize; + +template +struct specialize{}>::type> : rocm::bool_constant +{ +}; + +template +struct specialize{}>::type> : rocm::bool_constant +{ +}; + +template +static constexpr typename rocm::enable_if{}, bool>::type returns(T) +{ + return true; +} + +template +static constexpr typename rocm::enable_if{}, bool>::type returns(T) +{ + return false; +} + +template +static constexpr rocm::enable_if_t{}, bool> alias(T) +{ + return true; +} + +template +static constexpr rocm::enable_if_t{}, bool> alias(T) +{ + return false; +} + +TEST_CASE(test) +{ + EXPECT(not construct(1).value()); + EXPECT(construct(1L).value()); + EXPECT(not specialize{}); + EXPECT(specialize{}); + EXPECT(not returns(1)); + EXPECT(returns(1L)); + EXPECT(not alias(1)); + EXPECT(alias(1L)); +} diff --git a/test/gpu/kernels/rocm/functional/operations.cpp b/test/gpu/kernels/rocm/functional/operations.cpp new file mode 100644 index 00000000000..42b7fada6dd --- /dev/null +++ b/test/gpu/kernels/rocm/functional/operations.cpp @@ -0,0 +1,337 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2025-2026 Advanced Micro Devices, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#include +#include +#include + +template +struct has_is_transparent : rocm::bool_constant +{ +}; + +template +struct has_is_transparent : rocm::bool_constant +{ +}; + +// Arithmetic binary operations + +TEST_CASE(plus_typed) +{ + constexpr auto op = rocm::plus{}; + EXPECT(op(3, 5) == 8); + EXPECT(op(-3, 3) == 0); + EXPECT(op(0, 0) == 0); + EXPECT(op(-2, -3) == -5); + static_assert(rocm::plus{}(10, 20) == 30); +} + +TEST_CASE(minus_typed) +{ + constexpr auto op = rocm::minus{}; + EXPECT(op(5, 3) == 2); + EXPECT(op(3, 5) == -2); + EXPECT(op(0, 0) == 0); + EXPECT(op(-2, -3) == 1); + static_assert(rocm::minus{}(10, 3) == 7); +} + +TEST_CASE(multiplies_typed) +{ + constexpr auto op = rocm::multiplies{}; + EXPECT(op(3, 5) == 15); + EXPECT(op(-3, 5) == -15); + EXPECT(op(0, 100) == 0); + EXPECT(op(1, 42) == 42); + static_assert(rocm::multiplies{}(6, 7) == 42); +} + +TEST_CASE(divides_typed) +{ + constexpr auto op = rocm::divides{}; + EXPECT(op(10, 2) == 5); + EXPECT(op(7, 2) == 3); + EXPECT(op(-10, 2) == -5); + EXPECT(op(0, 5) == 0); + static_assert(rocm::divides{}(20, 4) == 5); +} + +TEST_CASE(modulus_typed) +{ + constexpr auto op = rocm::modulus{}; + EXPECT(op(10, 3) == 1); + EXPECT(op(9, 3) == 0); + EXPECT(op(7, 2) == 1); + EXPECT(op(0, 5) == 0); + static_assert(rocm::modulus{}(10, 3) == 1); +} + +// Bitwise binary operations + +TEST_CASE(bit_and_typed) +{ + constexpr auto op = rocm::bit_and{}; + EXPECT(op(0b1100, 0b1010) == 0b1000); + EXPECT(op(0xFF, 0x0F) == 0x0F); + EXPECT(op(0, 0xFF) == 0); + EXPECT(op(0xFF, 0xFF) == 0xFF); +} + +TEST_CASE(bit_or_typed) +{ + constexpr auto op = rocm::bit_or{}; + EXPECT(op(0b1100, 0b1010) == 0b1110); + EXPECT(op(0xFF, 0x0F) == 0xFF); + EXPECT(op(0, 0xFF) == 0xFF); + EXPECT(op(0, 0) == 0); +} + +TEST_CASE(bit_xor_typed) +{ + constexpr auto op = rocm::bit_xor{}; + EXPECT(op(0b1100, 0b1010) == (0b1100 ^ 0b1010)); + EXPECT(op(0xFF, 0x0F) == (0xFF ^ 0x0F)); + EXPECT(op(0xFF, 0xFF) == 0); + EXPECT(op(0, 0) == 0); +} + +// Comparison operations + +TEST_CASE(equal_to_typed) +{ + constexpr auto op = rocm::equal_to{}; + EXPECT(op(5, 5)); + EXPECT(not op(5, 3)); + EXPECT(op(0, 0)); + EXPECT(op(-1, -1)); + static_assert(rocm::equal_to{}(5, 5)); +} + +TEST_CASE(not_equal_to_typed) +{ + constexpr auto op = rocm::not_equal_to{}; + EXPECT(op(5, 3)); + EXPECT(not op(5, 5)); + EXPECT(not op(0, 0)); + EXPECT(op(-1, 1)); +} + +TEST_CASE(greater_typed) +{ + constexpr auto op = rocm::greater{}; + EXPECT(op(5, 3)); + EXPECT(not op(3, 5)); + EXPECT(not op(5, 5)); + EXPECT(op(0, -1)); +} + +TEST_CASE(less_typed) +{ + constexpr auto op = rocm::less{}; + EXPECT(op(3, 5)); + EXPECT(not op(5, 3)); + EXPECT(not op(5, 5)); + EXPECT(op(-1, 0)); +} + +TEST_CASE(greater_equal_typed) +{ + constexpr auto op = rocm::greater_equal{}; + EXPECT(op(5, 3)); + EXPECT(op(5, 5)); + EXPECT(not op(3, 5)); + EXPECT(op(0, 0)); +} + +TEST_CASE(less_equal_typed) +{ + constexpr auto op = rocm::less_equal{}; + EXPECT(op(3, 5)); + EXPECT(op(5, 5)); + EXPECT(not op(5, 3)); + EXPECT(op(0, 0)); +} + +// Logical binary operations + +TEST_CASE(logical_and_typed) +{ + constexpr auto op = rocm::logical_and{}; + EXPECT(op(true, true)); + EXPECT(not op(true, false)); + EXPECT(not op(false, true)); + EXPECT(not op(false, false)); +} + +TEST_CASE(logical_or_typed) +{ + constexpr auto op = rocm::logical_or{}; + EXPECT(op(true, true)); + EXPECT(op(true, false)); + EXPECT(op(false, true)); + EXPECT(not op(false, false)); +} + +// Unary operations + +TEST_CASE(negate_typed) +{ + constexpr auto op = rocm::negate{}; + EXPECT(op(5) == -5); + EXPECT(op(-5) == 5); + EXPECT(op(0) == 0); + static_assert(rocm::negate{}(5) == -5); +} + +TEST_CASE(logical_not_typed) +{ + constexpr auto op = rocm::logical_not{}; + EXPECT(op(false)); + EXPECT(not op(true)); +} + +TEST_CASE(bit_not_typed) +{ + constexpr auto op = rocm::bit_not{}; + EXPECT(op(0) == ~0); + EXPECT(op(-1) == ~(-1)); + EXPECT(op(0b1100) == ~0b1100); +} + +// Return type checks for typed specializations + +TEST_CASE(arithmetic_return_types) +{ + EXPECT(rocm::is_same{}(1, 2)), int>{}); + EXPECT(rocm::is_same{}(1, 2)), int>{}); + EXPECT(rocm::is_same{}(1, 2)), int>{}); + EXPECT(rocm::is_same{}(1, 2)), int>{}); + EXPECT(rocm::is_same{}(1, 2)), int>{}); +} + +TEST_CASE(comparison_return_types) +{ + EXPECT(rocm::is_same{}(1, 2)), bool>{}); + EXPECT(rocm::is_same{}(1, 2)), bool>{}); + EXPECT(rocm::is_same{}(1, 2)), bool>{}); + EXPECT(rocm::is_same{}(1, 2)), bool>{}); + EXPECT(rocm::is_same{}(1, 2)), bool>{}); + EXPECT(rocm::is_same{}(1, 2)), bool>{}); + EXPECT(rocm::is_same{}(true, false)), bool>{}); + EXPECT(rocm::is_same{}(true, false)), bool>{}); +} + +TEST_CASE(unary_return_types) +{ + EXPECT(rocm::is_same{}(1)), int>{}); + EXPECT(rocm::is_same{}(true)), bool>{}); + EXPECT(rocm::is_same{}(1)), int>{}); +} + +// Transparent specialization (is_transparent) + +TEST_CASE(binary_arithmetic_is_transparent) +{ + EXPECT(has_is_transparent>{}); + EXPECT(has_is_transparent>{}); + EXPECT(has_is_transparent>{}); + EXPECT(has_is_transparent>{}); + EXPECT(has_is_transparent>{}); +} + +TEST_CASE(binary_bitwise_is_transparent) +{ + EXPECT(has_is_transparent>{}); + EXPECT(has_is_transparent>{}); + EXPECT(has_is_transparent>{}); +} + +TEST_CASE(binary_comparison_is_transparent) +{ + EXPECT(has_is_transparent>{}); + EXPECT(has_is_transparent>{}); + EXPECT(has_is_transparent>{}); + EXPECT(has_is_transparent>{}); + EXPECT(has_is_transparent>{}); + EXPECT(has_is_transparent>{}); +} + +TEST_CASE(binary_logical_is_transparent) +{ + EXPECT(has_is_transparent>{}); + EXPECT(has_is_transparent>{}); +} + +TEST_CASE(unary_is_transparent) +{ + EXPECT(has_is_transparent>{}); + EXPECT(has_is_transparent>{}); + EXPECT(has_is_transparent>{}); +} + +TEST_CASE(typed_not_transparent) +{ + EXPECT(not has_is_transparent>{}); + EXPECT(not has_is_transparent>{}); + EXPECT(not has_is_transparent>{}); + EXPECT(not has_is_transparent>{}); + EXPECT(not has_is_transparent>{}); +} + +// Default template argument resolves to void + +TEST_CASE(default_template_arg) +{ + EXPECT(rocm::is_same, rocm::plus>{}); + EXPECT(rocm::is_same, rocm::minus>{}); + EXPECT(rocm::is_same, rocm::multiplies>{}); + EXPECT(rocm::is_same, rocm::negate>{}); + EXPECT(rocm::is_same, rocm::logical_not>{}); +} + +// Bitwise operations return type for typed specializations + +TEST_CASE(bitwise_return_types) +{ + EXPECT(rocm::is_same{}(1, 2)), int>{}); + EXPECT(rocm::is_same{}(1, 2)), int>{}); + EXPECT(rocm::is_same{}(1, 2)), int>{}); +} + +// Operations with long type + +TEST_CASE(plus_long) +{ + constexpr auto op = rocm::plus{}; + EXPECT(op(100000L, 200000L) == 300000L); + EXPECT(op(-100000L, 100000L) == 0L); +} + +TEST_CASE(multiplies_long) +{ + constexpr auto op = rocm::multiplies{}; + EXPECT(op(10000L, 10000L) == 100000000L); + EXPECT(op(-1L, 42L) == -42L); +} diff --git a/test/gpu/kernels/rocm/integral_constant.cpp b/test/gpu/kernels/rocm/integral_constant.cpp new file mode 100644 index 00000000000..a0534c91da4 --- /dev/null +++ b/test/gpu/kernels/rocm/integral_constant.cpp @@ -0,0 +1,214 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2015-2026 Advanced Micro Devices, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#include +#include + +// NOLINTBEGIN(hicpp-signed-bitwise,modernize-use-bool-literals,readability-implicit-bool-conversion) +struct test_operators_with_value +{ + static_assert(rocm::true_type::value); + static_assert(not rocm::false_type::value); + + using one_type = rocm::integral_constant; + using two_type = rocm::integral_constant; + + // These assertions deliberately read ::value to verify the stored constant, which is the point + // of the test, so do not rewrite them as trait construction. + // cppcheck-suppress-begin migraphx-AvoidNestedValue + using not_true_type = decltype(not rocm::true_type()); + static_assert(not not_true_type::value); + + using true_type_and_false_type = decltype(rocm::true_type() and rocm::false_type()); + static_assert(not true_type_and_false_type::value); + using true_type_or_false_type = decltype(rocm::true_type() or rocm::false_type()); + static_assert(true_type_or_false_type::value); + + using not_two_type = decltype(not two_type()); + static_assert(not_two_type::value == (not 2)); + +// GCC confuses the complement operator with the destructor +#ifdef __clang__ + using compl_two_type = decltype(~two_type()); + static_assert(compl_two_type::value == (~2)); +#endif + + using unary_plus_two_type = decltype(+two_type()); + static_assert(unary_plus_two_type::value == (+2)); + using unary_subtract_two_type = decltype(-two_type()); + static_assert(unary_subtract_two_type::value == (-2)); + + using one_type_add_two_type = decltype(one_type() + two_type()); + static_assert(one_type_add_two_type::value == (1 + 2)); + using one_type_subtract_two_type = decltype(one_type() - two_type()); + static_assert(one_type_subtract_two_type::value == (1 - 2)); + using one_type_multiply_two_type = decltype(one_type() * two_type()); + static_assert(one_type_multiply_two_type::value == (1 * 2)); + using one_type_divide_two_type = decltype(one_type() / two_type()); + static_assert(one_type_divide_two_type::value == (1 / 2)); + using one_type_remainder_two_type = decltype(one_type() % two_type()); + static_assert(one_type_remainder_two_type::value == (1 % 2)); + using one_type_shift_right_two_type = decltype(one_type() >> two_type()); + static_assert(one_type_shift_right_two_type::value == (1 >> 2)); + using one_type_shift_left_two_type = decltype(one_type() << two_type()); + static_assert(one_type_shift_left_two_type::value == (1 << 2)); + using one_type_greater_than_two_type = decltype(one_type() > two_type()); + static_assert(one_type_greater_than_two_type::value == (1 > 2)); + using one_type_less_than_two_type = decltype(one_type() < two_type()); + static_assert(one_type_less_than_two_type::value == (1 < 2)); + using one_type_less_than_equal_two_type = decltype(one_type() <= two_type()); + static_assert(one_type_less_than_equal_two_type::value == (1 <= 2)); + using one_type_greater_than_equal_two_type = decltype(one_type() >= two_type()); + static_assert(one_type_greater_than_equal_two_type::value == (1 >= 2)); + using one_type_equal_two_type = decltype(one_type() == two_type()); + static_assert(one_type_equal_two_type::value == (1 == 2)); + using one_type_not_equal_two_type = decltype(one_type() != two_type()); + static_assert(one_type_not_equal_two_type::value == (1 != 2)); + using one_type_bit_and_two_type = decltype(one_type() & two_type()); + static_assert(one_type_bit_and_two_type::value == (1 & 2)); + using one_type_xor_two_type = decltype(one_type() ^ two_type()); + static_assert(one_type_xor_two_type::value == (1 ^ 2)); + using one_type_bit_or_two_type = decltype(one_type() | two_type()); + static_assert(one_type_bit_or_two_type::value == (1 | 2)); + // cppcheck-suppress-end migraphx-AvoidNestedValue +}; + +// NOLINTEND(hicpp-signed-bitwise,modernize-use-bool-literals,readability-implicit-bool-conversion) + +// NOLINTBEGIN(hicpp-signed-bitwise,modernize-use-bool-literals,readability-implicit-bool-conversion) +struct test_operators_implicit_conversion +{ + static_assert(rocm::true_type()); + static_assert(not rocm::false_type()); + + using one_type = rocm::integral_constant; + using two_type = rocm::integral_constant; + + using not_true_type = decltype(not rocm::true_type()); + static_assert(not not_true_type()); + + using true_type_and_false_type = decltype(rocm::true_type() and rocm::false_type()); + static_assert(not true_type_and_false_type()); + using true_type_or_false_type = decltype(rocm::true_type() or rocm::false_type()); + static_assert(true_type_or_false_type()); + + using not_two_type = decltype(not two_type()); + static_assert(not_two_type() == (not 2)); + +// GCC confuses the complement operator with the destructor +#ifdef __clang__ + using compl_two_type = decltype(~two_type()); + static_assert(compl_two_type() == (~2)); +#endif + + using unary_plus_two_type = decltype(+two_type()); + static_assert(unary_plus_two_type() == (+2)); + using unary_subtract_two_type = decltype(-two_type()); + static_assert(unary_subtract_two_type() == (-2)); + + using one_type_add_two_type = decltype(one_type() + two_type()); + static_assert(one_type_add_two_type() == (1 + 2)); + using one_type_subtract_two_type = decltype(one_type() - two_type()); + static_assert(one_type_subtract_two_type() == (1 - 2)); + using one_type_multiply_two_type = decltype(one_type() * two_type()); + static_assert(one_type_multiply_two_type() == (1 * 2)); + using one_type_divide_two_type = decltype(one_type() / two_type()); + static_assert(one_type_divide_two_type() == (1 / 2)); + using one_type_remainder_two_type = decltype(one_type() % two_type()); + static_assert(one_type_remainder_two_type() == (1 % 2)); + using one_type_shift_right_two_type = decltype(one_type() >> two_type()); + static_assert(one_type_shift_right_two_type() == (1 >> 2)); + using one_type_shift_left_two_type = decltype(one_type() << two_type()); + static_assert(one_type_shift_left_two_type() == (1 << 2)); + using one_type_greater_than_two_type = decltype(one_type() > two_type()); + static_assert(one_type_greater_than_two_type() == (1 > 2)); + using one_type_less_than_two_type = decltype(one_type() < two_type()); + static_assert(one_type_less_than_two_type() == (1 < 2)); + using one_type_less_than_equal_two_type = decltype(one_type() <= two_type()); + static_assert(one_type_less_than_equal_two_type() == (1 <= 2)); + using one_type_greater_than_equal_two_type = decltype(one_type() >= two_type()); + static_assert(one_type_greater_than_equal_two_type() == (1 >= 2)); + using one_type_equal_two_type = decltype(one_type() == two_type()); + static_assert(one_type_equal_two_type() == (1 == 2)); + using one_type_not_equal_two_type = decltype(one_type() != two_type()); + static_assert(one_type_not_equal_two_type() == (1 != 2)); + using one_type_bit_and_two_type = decltype(one_type() & two_type()); + static_assert(one_type_bit_and_two_type() == (1 & 2)); + using one_type_xor_two_type = decltype(one_type() ^ two_type()); + static_assert(one_type_xor_two_type() == (1 ^ 2)); + using one_type_bit_or_two_type = decltype(one_type() | two_type()); + static_assert(one_type_bit_or_two_type() == (1 | 2)); +}; + +// NOLINTEND(hicpp-signed-bitwise,modernize-use-bool-literals,readability-implicit-bool-conversion) + +// NOLINTBEGIN(hicpp-signed-bitwise,modernize-use-bool-literals,readability-implicit-bool-conversion) +struct test_operators_with_integrals +{ + using one_type = rocm::integral_constant; + using two_type = rocm::integral_constant; + + // Double negation is intentional here to exercise the operators under test. + // cppcheck-suppress migraphx-MultipleUnaryOperator + static_assert(not(not rocm::true_type())); + + static_assert(not(rocm::true_type() and rocm::false_type())); + static_assert((rocm::true_type() or rocm::false_type())); + + static_assert((not two_type()) == (not 2)); + +// GCC confuses the complement operator with the destructor +#ifdef __clang__ + static_assert((~two_type()) == (~2)); +#endif + + static_assert((+two_type()) == (+2)); + static_assert((-two_type()) == (-2)); + + static_assert((one_type() + two_type()) == (1 + 2)); + static_assert((one_type() - two_type()) == (1 - 2)); + static_assert((one_type() * two_type()) == (1 * 2)); + static_assert((one_type() / two_type()) == (1 / 2)); + static_assert((one_type() % two_type()) == (1 % 2)); + static_assert((one_type() >> two_type()) == (1 >> 2)); + static_assert((one_type() << two_type()) == (1 << 2)); + static_assert((one_type() > two_type()) == (1 > 2)); + static_assert((one_type() < two_type()) == (1 < 2)); + static_assert((one_type() <= two_type()) == (1 <= 2)); + static_assert((one_type() >= two_type()) == (1 >= 2)); + static_assert((one_type() == two_type()) == (1 == 2)); + static_assert((one_type() != two_type()) == (1 != 2)); + static_assert((one_type() & two_type()) == (1 & 2)); + static_assert((one_type() ^ two_type()) == (1 ^ 2)); + static_assert((one_type() | two_type()) == (1 | 2)); +}; +// NOLINTEND(hicpp-signed-bitwise,modernize-use-bool-literals,readability-implicit-bool-conversion) + +TEST_CASE(bool_constant) +{ + EXPECT(rocm::bool_constant{}); + EXPECT(not rocm::bool_constant{}); + EXPECT(rocm::bool_constant{} == rocm::true_type{}); + EXPECT(rocm::bool_constant{} == rocm::false_type{}); +} diff --git a/test/gpu/kernels/rocm/iterator/iterator_traits.cpp b/test/gpu/kernels/rocm/iterator/iterator_traits.cpp new file mode 100644 index 00000000000..362908fa57a --- /dev/null +++ b/test/gpu/kernels/rocm/iterator/iterator_traits.cpp @@ -0,0 +1,177 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2025-2026 Advanced Micro Devices, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#include +#include + +// ---- Iterator category tag hierarchy ---- + +TEST_CASE(tag_hierarchy) +{ + EXPECT(rocm::is_base_of{}); + EXPECT(rocm::is_base_of{}); + EXPECT(rocm::is_base_of{}); + EXPECT(rocm::is_base_of{}); +} + +TEST_CASE(tag_not_related) +{ + EXPECT(not rocm::is_base_of{}); + EXPECT(not rocm::is_base_of{}); + EXPECT(not rocm::is_base_of{}); +} + +// ---- Pointer specialization: non-const ---- + +TEST_CASE(pointer_difference_type) +{ + EXPECT(rocm::is_same::difference_type, rocm::ptrdiff_t>{}); +} + +TEST_CASE(pointer_value_type) +{ + EXPECT(rocm::is_same::value_type, int>{}); +} + +TEST_CASE(pointer_pointer_type) +{ + EXPECT(rocm::is_same::pointer, int*>{}); +} + +TEST_CASE(pointer_reference_type) +{ + EXPECT(rocm::is_same::reference, int&>{}); +} + +TEST_CASE(pointer_iterator_category) +{ + EXPECT(rocm::is_same::iterator_category, + rocm::random_access_iterator_tag>{}); +} + +// ---- Pointer specialization: const ---- + +TEST_CASE(const_pointer_value_type) +{ + EXPECT(rocm::is_same::value_type, int>{}); +} + +TEST_CASE(const_pointer_pointer_type) +{ + EXPECT(rocm::is_same::pointer, const int*>{}); +} + +TEST_CASE(const_pointer_reference_type) +{ + EXPECT(rocm::is_same::reference, const int&>{}); +} + +TEST_CASE(const_pointer_difference_type) +{ + EXPECT(rocm::is_same::difference_type, rocm::ptrdiff_t>{}); +} + +TEST_CASE(const_pointer_iterator_category) +{ + EXPECT(rocm::is_same::iterator_category, + rocm::random_access_iterator_tag>{}); +} + +// ---- Pointer specialization: volatile ---- + +TEST_CASE(volatile_pointer_value_type) +{ + EXPECT(rocm::is_same::value_type, int>{}); +} + +TEST_CASE(volatile_pointer_pointer_type) +{ + EXPECT(rocm::is_same::pointer, volatile int*>{}); +} + +TEST_CASE(volatile_pointer_reference_type) +{ + EXPECT(rocm::is_same::reference, volatile int&>{}); +} + +// ---- Pointer specialization: const volatile ---- + +TEST_CASE(const_volatile_pointer_value_type) +{ + EXPECT(rocm::is_same::value_type, int>{}); +} + +// ---- Pointer specialization: other types ---- + +TEST_CASE(float_pointer_value_type) +{ + EXPECT(rocm::is_same::value_type, float>{}); +} + +TEST_CASE(double_pointer_difference_type) +{ + EXPECT(rocm::is_same::difference_type, rocm::ptrdiff_t>{}); +} + +TEST_CASE(char_pointer_reference_type) +{ + EXPECT(rocm::is_same::reference, char&>{}); +} + +// ---- Primary template with custom iterator ---- + +struct mock_iterator +{ + using difference_type = int; + using value_type = double; + using pointer = double*; + using reference = double&; + using iterator_category = rocm::bidirectional_iterator_tag; +}; + +TEST_CASE(custom_iterator_difference_type) +{ + EXPECT(rocm::is_same::difference_type, int>{}); +} + +TEST_CASE(custom_iterator_value_type) +{ + EXPECT(rocm::is_same::value_type, double>{}); +} + +TEST_CASE(custom_iterator_pointer_type) +{ + EXPECT(rocm::is_same::pointer, double*>{}); +} + +TEST_CASE(custom_iterator_reference_type) +{ + EXPECT(rocm::is_same::reference, double&>{}); +} + +TEST_CASE(custom_iterator_category) +{ + EXPECT(rocm::is_same::iterator_category, + rocm::bidirectional_iterator_tag>{}); +} diff --git a/test/gpu/kernels/rocm/iterator/reverse_iterator.cpp b/test/gpu/kernels/rocm/iterator/reverse_iterator.cpp new file mode 100644 index 00000000000..d6b4571b306 --- /dev/null +++ b/test/gpu/kernels/rocm/iterator/reverse_iterator.cpp @@ -0,0 +1,325 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2025-2026 Advanced Micro Devices, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#include +#include + +// ---- Construction ---- + +TEST_CASE(default_construct) +{ + constexpr rocm::reverse_iterator ri{}; + EXPECT(ri.base() == nullptr); +} + +TEST_CASE(construct_from_pointer) +{ + int arr[] = {10, 20, 30}; + rocm::reverse_iterator ri(arr + 3); + EXPECT(ri.base() == arr + 3); +} + +TEST_CASE(copy_construct) +{ + int arr[] = {1, 2, 3}; + rocm::reverse_iterator ri1(arr + 3); + rocm::reverse_iterator ri2(ri1); + EXPECT(ri2.base() == arr + 3); +} + +// ---- Dereference ---- + +TEST_CASE(dereference) +{ + int arr[] = {10, 20, 30}; + rocm::reverse_iterator ri(arr + 3); + EXPECT(*ri == 30); +} + +TEST_CASE(dereference_middle) +{ + int arr[] = {10, 20, 30}; + rocm::reverse_iterator ri(arr + 2); + EXPECT(*ri == 20); +} + +TEST_CASE(dereference_first) +{ + int arr[] = {10, 20, 30}; + rocm::reverse_iterator ri(arr + 1); + EXPECT(*ri == 10); +} + +// ---- Subscript ---- + +TEST_CASE(subscript) +{ + int arr[] = {10, 20, 30, 40, 50}; + rocm::reverse_iterator ri(arr + 5); + EXPECT(ri[0] == 50); + EXPECT(ri[1] == 40); + EXPECT(ri[2] == 30); + EXPECT(ri[3] == 20); + EXPECT(ri[4] == 10); +} + +// ---- Pre-increment / Pre-decrement ---- + +TEST_CASE(pre_increment) +{ + int arr[] = {10, 20, 30}; + rocm::reverse_iterator ri(arr + 3); + EXPECT(*ri == 30); + ++ri; + EXPECT(*ri == 20); + ++ri; + EXPECT(*ri == 10); +} + +TEST_CASE(pre_decrement) +{ + int arr[] = {10, 20, 30}; + rocm::reverse_iterator ri(arr + 1); + EXPECT(*ri == 10); + --ri; + EXPECT(*ri == 20); + --ri; + EXPECT(*ri == 30); +} + +// ---- Post-increment / Post-decrement ---- + +TEST_CASE(post_increment) +{ + int arr[] = {10, 20, 30}; + rocm::reverse_iterator ri(arr + 3); + auto old = ri++; + EXPECT(*old == 30); + EXPECT(*ri == 20); +} + +TEST_CASE(post_decrement) +{ + int arr[] = {10, 20, 30}; + rocm::reverse_iterator ri(arr + 1); + auto old = ri--; + EXPECT(*old == 10); + EXPECT(*ri == 20); +} + +// ---- Compound assignment ---- + +TEST_CASE(plus_equal) +{ + int arr[] = {10, 20, 30, 40, 50}; + rocm::reverse_iterator ri(arr + 5); + EXPECT(*ri == 50); + ri += 3; + EXPECT(*ri == 20); +} + +TEST_CASE(minus_equal) +{ + int arr[] = {10, 20, 30, 40, 50}; + rocm::reverse_iterator ri(arr + 2); + EXPECT(*ri == 20); + ri -= 3; + EXPECT(*ri == 50); +} + +// ---- Arithmetic operators ---- + +TEST_CASE(add_offset) +{ + int arr[] = {10, 20, 30, 40, 50}; + rocm::reverse_iterator ri(arr + 5); + auto ri2 = ri + 2; + EXPECT(*ri2 == 30); +} + +TEST_CASE(offset_add) +{ + int arr[] = {10, 20, 30, 40, 50}; + rocm::reverse_iterator ri(arr + 5); + auto ri2 = 2 + ri; + EXPECT(*ri2 == 30); +} + +TEST_CASE(subtract_offset) +{ + int arr[] = {10, 20, 30, 40, 50}; + rocm::reverse_iterator ri(arr + 2); + auto ri2 = ri - 2; + EXPECT(*ri2 == 40); +} + +TEST_CASE(difference) +{ + int arr[] = {10, 20, 30, 40, 50}; + rocm::reverse_iterator rbegin(arr + 5); + rocm::reverse_iterator rend(arr); + EXPECT(rend - rbegin == 5); + EXPECT(rbegin - rend == -5); +} + +// ---- Comparison operators ---- + +TEST_CASE(equal) +{ + int arr[] = {1, 2, 3}; + rocm::reverse_iterator a(arr + 3); + rocm::reverse_iterator b(arr + 3); + rocm::reverse_iterator c(arr + 2); + EXPECT(a == b); + EXPECT(not(a == c)); +} + +TEST_CASE(not_equal) +{ + int arr[] = {1, 2, 3}; + rocm::reverse_iterator a(arr + 3); + rocm::reverse_iterator b(arr + 2); + EXPECT(a != b); + EXPECT(not(a != a)); +} + +TEST_CASE(less_than) +{ + int arr[] = {1, 2, 3}; + rocm::reverse_iterator rbegin(arr + 3); + rocm::reverse_iterator rend(arr); + EXPECT(rbegin < rend); + EXPECT(not(rend < rbegin)); + EXPECT(not(rbegin < rbegin)); +} + +TEST_CASE(greater_than) +{ + int arr[] = {1, 2, 3}; + rocm::reverse_iterator rbegin(arr + 3); + rocm::reverse_iterator rend(arr); + EXPECT(rend > rbegin); + EXPECT(not(rbegin > rend)); +} + +TEST_CASE(less_equal) +{ + int arr[] = {1, 2, 3}; + rocm::reverse_iterator rbegin(arr + 3); + rocm::reverse_iterator rend(arr); + EXPECT(rbegin <= rend); + EXPECT(rbegin <= rbegin); + EXPECT(not(rend <= rbegin)); +} + +TEST_CASE(greater_equal) +{ + int arr[] = {1, 2, 3}; + rocm::reverse_iterator rbegin(arr + 3); + rocm::reverse_iterator rend(arr); + EXPECT(rend >= rbegin); + EXPECT(rend >= rend); + EXPECT(not(rbegin >= rend)); +} + +// ---- make_reverse_iterator ---- + +TEST_CASE(make_reverse_iterator_test) +{ + int arr[] = {10, 20, 30}; + auto ri = rocm::make_reverse_iterator(arr + 3); + EXPECT(*ri == 30); +} + +// ---- base() ---- + +TEST_CASE(base) +{ + int arr[] = {10, 20, 30}; + rocm::reverse_iterator ri(arr + 2); + EXPECT(ri.base() == arr + 2); +} + +// ---- Full traversal ---- + +TEST_CASE(full_traversal) +{ + int arr[] = {1, 2, 3, 4, 5}; + rocm::reverse_iterator ri(arr + 5); + int expected = 5; + while(ri != rocm::reverse_iterator(arr)) + { + EXPECT(*ri == expected); + --expected; + ++ri; + } + EXPECT(expected == 0); +} + +// ---- constexpr evaluation via static_assert ---- + +TEST_CASE(constexpr_dereference) +{ + static constexpr int arr[] = {100, 200, 300}; + static_assert(*rocm::reverse_iterator(arr + 3) == 300); + static_assert(*rocm::reverse_iterator(arr + 2) == 200); + static_assert(*rocm::reverse_iterator(arr + 1) == 100); +} + +TEST_CASE(constexpr_subscript) +{ + static constexpr int arr[] = {10, 20, 30}; + static_assert(rocm::reverse_iterator(arr + 3)[0] == 30); + static_assert(rocm::reverse_iterator(arr + 3)[1] == 20); + static_assert(rocm::reverse_iterator(arr + 3)[2] == 10); +} + +TEST_CASE(constexpr_arithmetic) +{ + static constexpr int arr[] = {10, 20, 30, 40}; + static_assert(*(rocm::reverse_iterator(arr + 4) + 2) == 20); + static_assert(*(2 + rocm::reverse_iterator(arr + 4)) == 20); + static_assert(*(rocm::reverse_iterator(arr + 1) - 1) == 20); +} + +TEST_CASE(constexpr_comparison) +{ + static constexpr int arr[] = {1, 2, 3}; + static_assert(rocm::reverse_iterator(arr + 3) == + rocm::reverse_iterator(arr + 3)); + static_assert(rocm::reverse_iterator(arr + 3) != + rocm::reverse_iterator(arr + 2)); + static_assert(rocm::reverse_iterator(arr + 3) < + rocm::reverse_iterator(arr)); +} + +// ---- Single element ---- + +TEST_CASE(single_element) +{ + int arr[] = {42}; + rocm::reverse_iterator ri(arr + 1); + EXPECT(*ri == 42); + EXPECT(ri[0] == 42); +} diff --git a/test/gpu/kernels/rocm/numeric_limits.cpp b/test/gpu/kernels/rocm/numeric_limits.cpp new file mode 100644 index 00000000000..44e376db15b --- /dev/null +++ b/test/gpu/kernels/rocm/numeric_limits.cpp @@ -0,0 +1,119 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2015-2026 Advanced Micro Devices, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#include +#include +#include + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define ROCM_CHECK_NUMERIC_LIMITS_MEM(expected, ...) \ + static_assert(rocm::is_same>{}) + +template +static constexpr void test_numeric_limits() +{ + using nl = rocm::numeric_limits; + static_assert(nl::is_specialized == Specialized); + if constexpr(rocm::is_integral{}) + { + static_assert(nl::is_integer); + static_assert(nl::is_exact); + static_assert(nl::is_signed == not rocm::is_unsigned{}); + } + if constexpr(rocm::is_floating_point{}) + { + static_assert(not nl::is_integer); + static_assert(not nl::is_exact); + static_assert(nl::is_signed); + } + ROCM_CHECK_NUMERIC_LIMITS_MEM(bool, nl::is_specialized); + ROCM_CHECK_NUMERIC_LIMITS_MEM(int, nl::digits); + ROCM_CHECK_NUMERIC_LIMITS_MEM(int, nl::digits10); + ROCM_CHECK_NUMERIC_LIMITS_MEM(int, nl::max_digits10); + ROCM_CHECK_NUMERIC_LIMITS_MEM(bool, nl::is_signed); + ROCM_CHECK_NUMERIC_LIMITS_MEM(bool, nl::is_integer); + ROCM_CHECK_NUMERIC_LIMITS_MEM(bool, nl::is_exact); + ROCM_CHECK_NUMERIC_LIMITS_MEM(int, nl::radix); + ROCM_CHECK_NUMERIC_LIMITS_MEM(int, nl::min_exponent); + ROCM_CHECK_NUMERIC_LIMITS_MEM(int, nl::min_exponent10); + ROCM_CHECK_NUMERIC_LIMITS_MEM(int, nl::max_exponent); + ROCM_CHECK_NUMERIC_LIMITS_MEM(int, nl::max_exponent10); + ROCM_CHECK_NUMERIC_LIMITS_MEM(bool, nl::has_infinity); + ROCM_CHECK_NUMERIC_LIMITS_MEM(bool, nl::has_quiet_NaN); + ROCM_CHECK_NUMERIC_LIMITS_MEM(bool, nl::has_signaling_NaN); + ROCM_CHECK_NUMERIC_LIMITS_MEM(bool, nl::is_iec559); + ROCM_CHECK_NUMERIC_LIMITS_MEM(bool, nl::is_bounded); + ROCM_CHECK_NUMERIC_LIMITS_MEM(bool, nl::is_modulo); + ROCM_CHECK_NUMERIC_LIMITS_MEM(bool, nl::traps); + ROCM_CHECK_NUMERIC_LIMITS_MEM(bool, nl::tinyness_before); + ROCM_CHECK_NUMERIC_LIMITS_MEM(rocm::float_round_style, nl::round_style); + ROCM_CHECK_NUMERIC_LIMITS_MEM(U, nl::min()); + ROCM_CHECK_NUMERIC_LIMITS_MEM(U, nl::lowest()); + ROCM_CHECK_NUMERIC_LIMITS_MEM(U, nl::max()); + ROCM_CHECK_NUMERIC_LIMITS_MEM(U, nl::epsilon()); + ROCM_CHECK_NUMERIC_LIMITS_MEM(U, nl::round_error()); + ROCM_CHECK_NUMERIC_LIMITS_MEM(U, nl::infinity()); + ROCM_CHECK_NUMERIC_LIMITS_MEM(U, nl::quiet_NaN()); + ROCM_CHECK_NUMERIC_LIMITS_MEM(U, nl::signaling_NaN()); + ROCM_CHECK_NUMERIC_LIMITS_MEM(U, nl::denorm_min()); +} + +template +static constexpr void test_numeric_limits_all() +{ + test_numeric_limits(); + test_numeric_limits(); + test_numeric_limits(); + test_numeric_limits(); +} + +struct foo +{ +}; + +TEST_CASE(all) +{ + // test_numeric_limits_all(); + test_numeric_limits_all(); + test_numeric_limits_all(); + test_numeric_limits_all(); + test_numeric_limits_all(); + test_numeric_limits_all(); + test_numeric_limits_all(); + test_numeric_limits_all(); + test_numeric_limits_all(); + test_numeric_limits_all(); + test_numeric_limits_all(); + test_numeric_limits_all(); + test_numeric_limits_all(); + test_numeric_limits_all(); + test_numeric_limits_all(); + test_numeric_limits_all(); + test_numeric_limits_all(); +#ifdef __FLT16_MAX__ + test_numeric_limits_all<_Float16>(); +#endif + test_numeric_limits_all<__bf16>(); + test_numeric_limits_all(); +} diff --git a/test/gpu/kernels/rocm/std_numeric_limits.cpp b/test/gpu/kernels/rocm/std_numeric_limits.cpp new file mode 100644 index 00000000000..f17e85662c3 --- /dev/null +++ b/test/gpu/kernels/rocm/std_numeric_limits.cpp @@ -0,0 +1,101 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2015-2026 Advanced Micro Devices, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#pragma clang diagnostic ignored "-Wfloat-equal" + +#include +#include + +#ifdef __HIPCC_RTC__ + +template +TEST_CASE_TEMPLATE(test_numeric_limits) +{ +} + +#else + +#include +#include + +template +TEST_CASE_TEMPLATE(test_numeric_limits) +{ + EXPECT(std::numeric_limits::is_specialized == rocm::numeric_limits::is_specialized); + EXPECT(std::numeric_limits::digits == rocm::numeric_limits::digits); + EXPECT(std::numeric_limits::digits10 == rocm::numeric_limits::digits10); + EXPECT(std::numeric_limits::max_digits10 == rocm::numeric_limits::max_digits10); + EXPECT(std::numeric_limits::is_signed == rocm::numeric_limits::is_signed); + EXPECT(std::numeric_limits::is_integer == rocm::numeric_limits::is_integer); + EXPECT(std::numeric_limits::is_exact == rocm::numeric_limits::is_exact); + EXPECT(std::numeric_limits::radix == rocm::numeric_limits::radix); + EXPECT(std::numeric_limits::min_exponent == rocm::numeric_limits::min_exponent); + EXPECT(std::numeric_limits::min_exponent10 == rocm::numeric_limits::min_exponent10); + EXPECT(std::numeric_limits::max_exponent == rocm::numeric_limits::max_exponent); + EXPECT(std::numeric_limits::max_exponent10 == rocm::numeric_limits::max_exponent10); + EXPECT(std::numeric_limits::has_infinity == rocm::numeric_limits::has_infinity); + EXPECT(std::numeric_limits::has_quiet_NaN == rocm::numeric_limits::has_quiet_NaN); + EXPECT(std::numeric_limits::has_signaling_NaN == rocm::numeric_limits::has_signaling_NaN); + EXPECT(std::numeric_limits::is_iec559 == rocm::numeric_limits::is_iec559); + EXPECT(std::numeric_limits::is_bounded == rocm::numeric_limits::is_bounded); + EXPECT(std::numeric_limits::is_modulo == rocm::numeric_limits::is_modulo); + EXPECT(std::numeric_limits::tinyness_before == rocm::numeric_limits::tinyness_before); + + EXPECT(std::numeric_limits::min() == rocm::numeric_limits::min()); + EXPECT(std::numeric_limits::lowest() == rocm::numeric_limits::lowest()); + EXPECT(std::numeric_limits::max() == rocm::numeric_limits::max()); + EXPECT(std::numeric_limits::epsilon() == rocm::numeric_limits::epsilon()); + EXPECT(std::numeric_limits::round_error() == rocm::numeric_limits::round_error()); + EXPECT(std::numeric_limits::infinity() == rocm::numeric_limits::infinity()); + EXPECT(std::numeric_limits::denorm_min() == rocm::numeric_limits::denorm_min()); + if constexpr(std::is_floating_point{}) + { + EXPECT(std::isnan(rocm::numeric_limits::quiet_NaN())); + EXPECT(std::isnan(rocm::numeric_limits::signaling_NaN())); + } + else + { + EXPECT(std::numeric_limits::quiet_NaN() == rocm::numeric_limits::quiet_NaN()); + EXPECT(std::numeric_limits::signaling_NaN() == rocm::numeric_limits::signaling_NaN()); + } +} +#endif + +TEST_CASE_REGISTER(test_numeric_limits); +TEST_CASE_REGISTER(test_numeric_limits); +TEST_CASE_REGISTER(test_numeric_limits); +TEST_CASE_REGISTER(test_numeric_limits); +TEST_CASE_REGISTER(test_numeric_limits); +TEST_CASE_REGISTER(test_numeric_limits); +TEST_CASE_REGISTER(test_numeric_limits); +TEST_CASE_REGISTER(test_numeric_limits); +TEST_CASE_REGISTER(test_numeric_limits); +TEST_CASE_REGISTER(test_numeric_limits); +TEST_CASE_REGISTER(test_numeric_limits); +TEST_CASE_REGISTER(test_numeric_limits); +TEST_CASE_REGISTER(test_numeric_limits); +TEST_CASE_REGISTER(test_numeric_limits); +TEST_CASE_REGISTER(test_numeric_limits); +TEST_CASE_REGISTER(test_numeric_limits); diff --git a/test/gpu/kernels/rocm/stdint.cpp b/test/gpu/kernels/rocm/stdint.cpp new file mode 100644 index 00000000000..f6b47b6bed8 --- /dev/null +++ b/test/gpu/kernels/rocm/stdint.cpp @@ -0,0 +1,38 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2015-2026 Advanced Micro Devices, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#include +#include + +TEST_CASE(sizes) +{ + static_assert(sizeof(rocm::int8_t) == 1, "int8_t must be 1 bytes"); + static_assert(sizeof(rocm::uint8_t) == 1, "uint8_t must be 1 bytes"); + static_assert(sizeof(rocm::int16_t) == 2, "int16_t must be 2 bytes"); + static_assert(sizeof(rocm::uint16_t) == 2, "uint16_t must be 2 bytes"); + static_assert(sizeof(rocm::int32_t) == 4, "int32_t must be 4 bytes"); + static_assert(sizeof(rocm::uint32_t) == 4, "uint32_t must be 4 bytes"); + static_assert(sizeof(rocm::int64_t) == 8, "int64_t must be 8 bytes"); + static_assert(sizeof(rocm::uint64_t) == 8, "uint64_t must be 8 bytes"); +} diff --git a/test/gpu/kernels/rocm/type_traits.cpp b/test/gpu/kernels/rocm/type_traits.cpp new file mode 100644 index 00000000000..85df103156a --- /dev/null +++ b/test/gpu/kernels/rocm/type_traits.cpp @@ -0,0 +1,481 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2025-2026 Advanced Micro Devices, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include +#include + +namespace test_tt { + +template +struct is_same +{ + constexpr operator bool() const noexcept { return false; } +}; + +template +struct is_same +{ + constexpr operator bool() const noexcept { return true; } +}; + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define ROCM_CHECK_TYPE(...) EXPECT(test_tt::is_same<__VA_ARGS__>{}) + +enum enum1 +{ + enum1_one, + enum1_two +}; + +struct udt +{ + udt(); + ~udt(); + udt(const udt&); + udt& operator=(const udt&); + int i; + + void f1(); + int f2(); + int f3(int); + int f4(int, float); +}; + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wredundant-parens" +using f1 = void (*)(); +using f2 = int (*)(int); +using f3 = int (*)(int, bool); +using mf1 = void (udt::*)(); +using mf2 = int (udt::*)(); +using mf3 = int (udt::*)(int); +using mf4 = int (udt::*)(int, float); +using mp = int(udt::*); +using cmf = int (udt::*)(int) const; +using mf8 = int (udt::*)(...); +#pragma clang diagnostic pop + +using foo0_t = void(); +using foo1_t = void(int); +using foo2_t = void(int&, double); +using foo3_t = void(int&, bool, int, int); +using foo4_t = void(int, bool, int*, int*, int, int, int, int, int); + +struct incomplete_type; + +// clang-format off +#define ROCM_VISIT_TYPES(m, ...) \ + m(bool, __VA_ARGS__) \ + m(char, __VA_ARGS__) \ + m(wchar_t, __VA_ARGS__) \ + m(signed char, __VA_ARGS__) \ + m(unsigned char, __VA_ARGS__) \ + m(short, __VA_ARGS__) \ + m(unsigned short, __VA_ARGS__) \ + m(int, __VA_ARGS__) \ + m(unsigned int, __VA_ARGS__) \ + m(long, __VA_ARGS__) \ + m(unsigned long, __VA_ARGS__) \ + m(float, __VA_ARGS__) \ + m(long double, __VA_ARGS__) \ + m(double, __VA_ARGS__) \ + m(test_tt::udt, __VA_ARGS__) \ + m(test_tt::enum1, __VA_ARGS__) +// clang-format on + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define ROCM_TRANSFORM_CHECK_VISITOR(x, name, from_suffix, to_suffix) \ + ROCM_CHECK_TYPE(x to_suffix, name::type); \ + ROCM_CHECK_TYPE(x to_suffix, name##_t); + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define ROCM_TRANSFORM_CHECK(name, from_suffix, to_suffix) \ + ROCM_VISIT_TYPES(ROCM_TRANSFORM_CHECK_VISITOR, name, from_suffix, to_suffix) + +} // namespace test_tt + +// NOLINTNEXTLINE(readability-function-size) +TEST_CASE(add_pointer) +{ + ROCM_TRANSFORM_CHECK(rocm::add_pointer, , *); + ROCM_TRANSFORM_CHECK(rocm::add_pointer, const, const*); + ROCM_TRANSFORM_CHECK(rocm::add_pointer, volatile, volatile*); + ROCM_TRANSFORM_CHECK(rocm::add_pointer, *, **); + ROCM_TRANSFORM_CHECK(rocm::add_pointer, * volatile, * volatile*); + ROCM_TRANSFORM_CHECK(rocm::add_pointer, const*, const**); + ROCM_TRANSFORM_CHECK(rocm::add_pointer, volatile*, volatile**); +} + +// NOLINTNEXTLINE(readability-function-size) +TEST_CASE(remove_pointer) +{ + // Non-pointer types are unchanged + ROCM_TRANSFORM_CHECK(rocm::remove_pointer, , ); + ROCM_TRANSFORM_CHECK(rocm::remove_pointer, const, const); + ROCM_TRANSFORM_CHECK(rocm::remove_pointer, volatile, volatile); + // Pointer types are stripped + ROCM_TRANSFORM_CHECK(rocm::remove_pointer, *, ); + ROCM_TRANSFORM_CHECK(rocm::remove_pointer, * const, ); + ROCM_TRANSFORM_CHECK(rocm::remove_pointer, * volatile, ); + // Pointer to cv-qualified types + ROCM_TRANSFORM_CHECK(rocm::remove_pointer, const*, const); + ROCM_TRANSFORM_CHECK(rocm::remove_pointer, volatile*, volatile); + // References are unchanged + ROCM_TRANSFORM_CHECK(rocm::remove_pointer, &, &); + ROCM_TRANSFORM_CHECK(rocm::remove_pointer, const&, const&); + ROCM_TRANSFORM_CHECK(rocm::remove_pointer, &&, &&); + ROCM_TRANSFORM_CHECK(rocm::remove_pointer, const&&, const&&); + // Arrays are unchanged + ROCM_TRANSFORM_CHECK(rocm::remove_pointer, const[2], const[2]); + ROCM_TRANSFORM_CHECK(rocm::remove_pointer, const[2][3], const[2][3]); + // References to arrays are unchanged + ROCM_TRANSFORM_CHECK(rocm::remove_pointer, (&)[2], (&)[2]); + ROCM_TRANSFORM_CHECK(rocm::remove_pointer, (&&)[2], (&&)[2]); + // Function pointers are stripped + ROCM_TRANSFORM_CHECK(rocm::remove_pointer, (*)(long), (long)); + ROCM_TRANSFORM_CHECK(rocm::remove_pointer, (*const)(long), (long)); +} + +struct c1 +{ +}; + +struct c2 +{ +}; + +struct c3 : c2 +{ +}; +struct c1c2 +{ + c1c2() {} + c1c2(c1 const&) {} + c1c2(c2 const&) {} + c1c2& operator=(c1c2 const&) = default; +}; + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define ROCM_CHECK_COMMON_TYPE(expected, ...) \ + ROCM_CHECK_TYPE(rocm::common_type<__VA_ARGS__>::type, expected); \ + ROCM_CHECK_TYPE(rocm::common_type_t<__VA_ARGS__>, expected); + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define ROCM_CHECK_COMMON_TYP_E2(expected, a, b) \ + ROCM_CHECK_COMMON_TYPE(expected, a, b); \ + ROCM_CHECK_COMMON_TYPE(expected, b, a); + +TEST_CASE(common_type) +{ + ROCM_CHECK_COMMON_TYPE(int, int); + ROCM_CHECK_COMMON_TYPE(int, int, int); + ROCM_CHECK_COMMON_TYPE(unsigned int, unsigned int, unsigned int); + ROCM_CHECK_COMMON_TYPE(double, double, double); + + ROCM_CHECK_COMMON_TYP_E2(c1c2, c1c2&, c1&); + ROCM_CHECK_COMMON_TYP_E2(c2*, c3*, c2*); + ROCM_CHECK_COMMON_TYP_E2(const int*, int*, const int*); + ROCM_CHECK_COMMON_TYP_E2(const volatile int*, volatile int*, const int*); + ROCM_CHECK_COMMON_TYP_E2(volatile int*, int*, volatile int*); + ROCM_CHECK_COMMON_TYP_E2(int, char, unsigned char); + ROCM_CHECK_COMMON_TYP_E2(int, char, short); + ROCM_CHECK_COMMON_TYP_E2(int, char, unsigned short); + ROCM_CHECK_COMMON_TYP_E2(int, char, int); + ROCM_CHECK_COMMON_TYP_E2(unsigned int, char, unsigned int); + ROCM_CHECK_COMMON_TYP_E2(double, double, unsigned int); + + ROCM_CHECK_COMMON_TYPE(double, double, char, int); + + ROCM_CHECK_COMMON_TYPE(int, int&); + ROCM_CHECK_COMMON_TYPE(int, const int); + ROCM_CHECK_COMMON_TYPE(int, const int, const int); + ROCM_CHECK_COMMON_TYP_E2(long, const int, const long); +} + +TEST_CASE(condition) +{ + EXPECT(rocm::is_same::type, int>{}); + EXPECT(rocm::is_same::type, long>{}); + EXPECT(not rocm::is_same::type, long>{}); + EXPECT(not rocm::is_same::type, int>{}); +} + +TEST_CASE(is_void) +{ + EXPECT(rocm::is_void{}); + EXPECT(rocm::is_void{}); + EXPECT(rocm::is_void{}); + EXPECT(rocm::is_void{}); + + EXPECT(not rocm::is_void{}); + EXPECT(not rocm::is_void{}); + EXPECT(not rocm::is_void{}); + EXPECT(not rocm::is_void{}); + EXPECT(not rocm::is_void{}); + EXPECT(not rocm::is_void{}); + EXPECT(not rocm::is_void{}); + EXPECT(not rocm::is_void{}); + EXPECT(not rocm::is_void{}); + EXPECT(not rocm::is_void{}); + EXPECT(not rocm::is_void{}); +} + +// NOLINTNEXTLINE(readability-function-size) +TEST_CASE(remove_cv) +{ + ROCM_TRANSFORM_CHECK(rocm::remove_cv, , ); + ROCM_TRANSFORM_CHECK(rocm::remove_cv, const, ); + ROCM_TRANSFORM_CHECK(rocm::remove_cv, volatile, ); + ROCM_TRANSFORM_CHECK(rocm::remove_cv, const volatile, ); + ROCM_TRANSFORM_CHECK(rocm::remove_cv, const&, const&); + ROCM_TRANSFORM_CHECK(rocm::remove_cv, * const, *); + ROCM_TRANSFORM_CHECK(rocm::remove_cv, * volatile, *); + ROCM_TRANSFORM_CHECK(rocm::remove_cv, * const volatile, *); + ROCM_TRANSFORM_CHECK(rocm::remove_cv, *, *); + ROCM_TRANSFORM_CHECK(rocm::remove_cv, const*, const*); + ROCM_TRANSFORM_CHECK(rocm::remove_cv, volatile*, volatile*); + ROCM_TRANSFORM_CHECK(rocm::remove_cv, const[2], [2]); + ROCM_TRANSFORM_CHECK(rocm::remove_cv, volatile[2], [2]); + ROCM_TRANSFORM_CHECK(rocm::remove_cv, const volatile[2], [2]); + ROCM_TRANSFORM_CHECK(rocm::remove_cv, [2], [2]); + ROCM_TRANSFORM_CHECK(rocm::remove_cv, const*, const*); + ROCM_TRANSFORM_CHECK(rocm::remove_cv, const* volatile, const*); + ROCM_TRANSFORM_CHECK(rocm::remove_cv, const&&, const&&); +} + +// NOLINTNEXTLINE(readability-function-size) +TEST_CASE(remove_reference) +{ + ROCM_TRANSFORM_CHECK(rocm::remove_reference, , ); + ROCM_TRANSFORM_CHECK(rocm::remove_reference, &, ); + ROCM_TRANSFORM_CHECK(rocm::remove_reference, &&, ); + ROCM_TRANSFORM_CHECK(rocm::remove_reference, const, const); + ROCM_TRANSFORM_CHECK(rocm::remove_reference, volatile, volatile); + ROCM_TRANSFORM_CHECK(rocm::remove_reference, const&, const); + ROCM_TRANSFORM_CHECK(rocm::remove_reference, *, *); + ROCM_TRANSFORM_CHECK(rocm::remove_reference, * volatile, * volatile); + ROCM_TRANSFORM_CHECK(rocm::remove_reference, const&, const); + ROCM_TRANSFORM_CHECK(rocm::remove_reference, const*, const*); + ROCM_TRANSFORM_CHECK(rocm::remove_reference, volatile*, volatile*); + ROCM_TRANSFORM_CHECK(rocm::remove_reference, const[2], const[2]); + ROCM_TRANSFORM_CHECK(rocm::remove_reference, (&)[2], [2]); + ROCM_TRANSFORM_CHECK(rocm::remove_reference, const&&, const); + ROCM_TRANSFORM_CHECK(rocm::remove_reference, const&&, const); + ROCM_TRANSFORM_CHECK(rocm::remove_reference, (&&)[2], [2]); +} + +// NOLINTNEXTLINE(readability-function-size) +TEST_CASE(remove_cvref) +{ + // cv-qualifiers stripped + ROCM_TRANSFORM_CHECK(rocm::remove_cvref, , ); + ROCM_TRANSFORM_CHECK(rocm::remove_cvref, const, ); + ROCM_TRANSFORM_CHECK(rocm::remove_cvref, volatile, ); + ROCM_TRANSFORM_CHECK(rocm::remove_cvref, const volatile, ); + // lvalue references with cv-qualifiers stripped + ROCM_TRANSFORM_CHECK(rocm::remove_cvref, &, ); + ROCM_TRANSFORM_CHECK(rocm::remove_cvref, const&, ); + ROCM_TRANSFORM_CHECK(rocm::remove_cvref, volatile&, ); + ROCM_TRANSFORM_CHECK(rocm::remove_cvref, const volatile&, ); + // rvalue references with cv-qualifiers stripped + ROCM_TRANSFORM_CHECK(rocm::remove_cvref, &&, ); + ROCM_TRANSFORM_CHECK(rocm::remove_cvref, const&&, ); + ROCM_TRANSFORM_CHECK(rocm::remove_cvref, volatile&&, ); + ROCM_TRANSFORM_CHECK(rocm::remove_cvref, const volatile&&, ); + // Pointer top-level cv stripped + ROCM_TRANSFORM_CHECK(rocm::remove_cvref, *, *); + ROCM_TRANSFORM_CHECK(rocm::remove_cvref, * const, *); + ROCM_TRANSFORM_CHECK(rocm::remove_cvref, * volatile, *); + ROCM_TRANSFORM_CHECK(rocm::remove_cvref, * const volatile, *); + // Pointer top-level cv stripped via lvalue ref + ROCM_TRANSFORM_CHECK(rocm::remove_cvref, *&, *); + ROCM_TRANSFORM_CHECK(rocm::remove_cvref, * const&, *); + ROCM_TRANSFORM_CHECK(rocm::remove_cvref, * volatile&, *); + ROCM_TRANSFORM_CHECK(rocm::remove_cvref, * const volatile&, *); + // Pointer top-level cv stripped via rvalue ref + ROCM_TRANSFORM_CHECK(rocm::remove_cvref, *&&, *); + ROCM_TRANSFORM_CHECK(rocm::remove_cvref, * const&&, *); + ROCM_TRANSFORM_CHECK(rocm::remove_cvref, * volatile&&, *); + ROCM_TRANSFORM_CHECK(rocm::remove_cvref, * const volatile&&, *); + // Pointee cv-qualifiers preserved + ROCM_TRANSFORM_CHECK(rocm::remove_cvref, const*, const*); + ROCM_TRANSFORM_CHECK(rocm::remove_cvref, volatile*, volatile*); + ROCM_TRANSFORM_CHECK(rocm::remove_cvref, const* const, const*); + ROCM_TRANSFORM_CHECK(rocm::remove_cvref, const* volatile, const*); + // Pointee cv-qualifiers preserved via lvalue ref + ROCM_TRANSFORM_CHECK(rocm::remove_cvref, const*&, const*); + ROCM_TRANSFORM_CHECK(rocm::remove_cvref, volatile*&, volatile*); + ROCM_TRANSFORM_CHECK(rocm::remove_cvref, const* const&, const*); + ROCM_TRANSFORM_CHECK(rocm::remove_cvref, const* volatile&, const*); + // Pointee cv-qualifiers preserved via rvalue ref + ROCM_TRANSFORM_CHECK(rocm::remove_cvref, const*&&, const*); + ROCM_TRANSFORM_CHECK(rocm::remove_cvref, volatile * &&, volatile*); + ROCM_TRANSFORM_CHECK(rocm::remove_cvref, const* const&&, const*); + ROCM_TRANSFORM_CHECK(rocm::remove_cvref, const* volatile&&, const*); + // Arrays with cv-qualifiers stripped + ROCM_TRANSFORM_CHECK(rocm::remove_cvref, [2], [2]); + ROCM_TRANSFORM_CHECK(rocm::remove_cvref, const[2], [2]); + ROCM_TRANSFORM_CHECK(rocm::remove_cvref, volatile[2], [2]); + ROCM_TRANSFORM_CHECK(rocm::remove_cvref, const volatile[2], [2]); + // Arrays via lvalue ref with cv-qualifiers stripped + ROCM_TRANSFORM_CHECK(rocm::remove_cvref, (&)[2], [2]); + ROCM_TRANSFORM_CHECK(rocm::remove_cvref, const(&)[2], [2]); + ROCM_TRANSFORM_CHECK(rocm::remove_cvref, volatile(&)[2], [2]); + ROCM_TRANSFORM_CHECK(rocm::remove_cvref, const volatile(&)[2], [2]); + // Arrays via rvalue ref with cv-qualifiers stripped + ROCM_TRANSFORM_CHECK(rocm::remove_cvref, (&&)[2], [2]); + ROCM_TRANSFORM_CHECK(rocm::remove_cvref, const(&&)[2], [2]); + ROCM_TRANSFORM_CHECK(rocm::remove_cvref, volatile(&&)[2], [2]); + ROCM_TRANSFORM_CHECK(rocm::remove_cvref, const volatile(&&)[2], [2]); +} + +// NOLINTNEXTLINE(readability-function-size) +TEST_CASE(add_const) +{ + // Plain types get const + ROCM_TRANSFORM_CHECK(rocm::add_const, , const); + // Already const is idempotent + ROCM_TRANSFORM_CHECK(rocm::add_const, const, const); + // Volatile gets const added + ROCM_TRANSFORM_CHECK(rocm::add_const, volatile, const volatile); + // Pointers get const on the pointer + ROCM_TRANSFORM_CHECK(rocm::add_const, *, * const); + ROCM_TRANSFORM_CHECK(rocm::add_const, * volatile, * const volatile); + // Already const pointer is idempotent + ROCM_TRANSFORM_CHECK(rocm::add_const, * const, * const); + // Pointer-to-cv gets const on the pointer + ROCM_TRANSFORM_CHECK(rocm::add_const, const*, const* const); + ROCM_TRANSFORM_CHECK(rocm::add_const, volatile*, volatile* const); + // References are unchanged + ROCM_TRANSFORM_CHECK(rocm::add_const, &, &); + ROCM_TRANSFORM_CHECK(rocm::add_const, const&, const&); + ROCM_TRANSFORM_CHECK(rocm::add_const, volatile&, volatile&); + ROCM_TRANSFORM_CHECK(rocm::add_const, &&, &&); + ROCM_TRANSFORM_CHECK(rocm::add_const, const&&, const&&); + // Arrays get const on element type + ROCM_TRANSFORM_CHECK(rocm::add_const, [2], const[2]); + ROCM_TRANSFORM_CHECK(rocm::add_const, const[2], const[2]); + ROCM_TRANSFORM_CHECK(rocm::add_const, [2][3], const[2][3]); + // Reference to array unchanged + ROCM_TRANSFORM_CHECK(rocm::add_const, (&)[2], (&)[2]); +} + +// NOLINTNEXTLINE(readability-function-size) +TEST_CASE(add_volatile) +{ + // Plain types get volatile + ROCM_TRANSFORM_CHECK(rocm::add_volatile, , volatile); + // Const gets volatile added + ROCM_TRANSFORM_CHECK(rocm::add_volatile, const, const volatile); + // Already volatile is idempotent + ROCM_TRANSFORM_CHECK(rocm::add_volatile, volatile, volatile); + // Pointers get volatile on the pointer + ROCM_TRANSFORM_CHECK(rocm::add_volatile, *, * volatile); + ROCM_TRANSFORM_CHECK(rocm::add_volatile, * const, * const volatile); + // Already volatile pointer is idempotent + ROCM_TRANSFORM_CHECK(rocm::add_volatile, * volatile, * volatile); + // Pointer-to-cv gets volatile on the pointer + ROCM_TRANSFORM_CHECK(rocm::add_volatile, const*, const* volatile); + ROCM_TRANSFORM_CHECK(rocm::add_volatile, volatile*, volatile* volatile); + // References are unchanged + ROCM_TRANSFORM_CHECK(rocm::add_volatile, &, &); + ROCM_TRANSFORM_CHECK(rocm::add_volatile, const&, const&); + ROCM_TRANSFORM_CHECK(rocm::add_volatile, volatile&, volatile&); + ROCM_TRANSFORM_CHECK(rocm::add_volatile, &&, &&); + // Arrays get volatile on element type + ROCM_TRANSFORM_CHECK(rocm::add_volatile, [2], volatile[2]); + ROCM_TRANSFORM_CHECK(rocm::add_volatile, const[2], const volatile[2]); + ROCM_TRANSFORM_CHECK(rocm::add_volatile, [2][3], volatile[2][3]); + // Reference to array unchanged + ROCM_TRANSFORM_CHECK(rocm::add_volatile, (&)[2], (&)[2]); +} + +// NOLINTNEXTLINE(readability-function-size) +TEST_CASE(add_cv) +{ + // Plain types get const volatile + ROCM_TRANSFORM_CHECK(rocm::add_cv, , const volatile); + // Const gets volatile added + ROCM_TRANSFORM_CHECK(rocm::add_cv, const, const volatile); + // Volatile gets const added + ROCM_TRANSFORM_CHECK(rocm::add_cv, volatile, const volatile); + // Pointers get const volatile on the pointer + ROCM_TRANSFORM_CHECK(rocm::add_cv, *, * const volatile); + ROCM_TRANSFORM_CHECK(rocm::add_cv, * volatile, * const volatile); + ROCM_TRANSFORM_CHECK(rocm::add_cv, * const, * const volatile); + // Pointer-to-cv gets const volatile on the pointer + ROCM_TRANSFORM_CHECK(rocm::add_cv, const*, const* const volatile); + ROCM_TRANSFORM_CHECK(rocm::add_cv, volatile*, volatile* const volatile); + // References are unchanged + ROCM_TRANSFORM_CHECK(rocm::add_cv, &, &); + ROCM_TRANSFORM_CHECK(rocm::add_cv, const&, const&); + ROCM_TRANSFORM_CHECK(rocm::add_cv, volatile&, volatile&); + ROCM_TRANSFORM_CHECK(rocm::add_cv, &&, &&); + ROCM_TRANSFORM_CHECK(rocm::add_cv, const&&, const&&); + // Arrays get const volatile on element type + ROCM_TRANSFORM_CHECK(rocm::add_cv, [2], const volatile[2]); + ROCM_TRANSFORM_CHECK(rocm::add_cv, const[2], const volatile[2]); + ROCM_TRANSFORM_CHECK(rocm::add_cv, [2][3], const volatile[2][3]); + // Reference to array unchanged + ROCM_TRANSFORM_CHECK(rocm::add_cv, (&)[2], (&)[2]); +} + +// NOLINTNEXTLINE(readability-function-size) +TEST_CASE(type_identity) +{ + ROCM_TRANSFORM_CHECK(rocm::type_identity, , ); + ROCM_TRANSFORM_CHECK(rocm::type_identity, const, const); + ROCM_TRANSFORM_CHECK(rocm::type_identity, volatile, volatile); + ROCM_TRANSFORM_CHECK(rocm::type_identity, const volatile, const volatile); + ROCM_TRANSFORM_CHECK(rocm::type_identity, [], []); + ROCM_TRANSFORM_CHECK(rocm::type_identity, * const, * const); + ROCM_TRANSFORM_CHECK(rocm::type_identity, * volatile, * volatile); + ROCM_TRANSFORM_CHECK(rocm::type_identity, * const volatile, * const volatile); + ROCM_TRANSFORM_CHECK(rocm::type_identity, *, *); + ROCM_TRANSFORM_CHECK(rocm::type_identity, volatile*, volatile*); + ROCM_TRANSFORM_CHECK(rocm::type_identity, const[2], const[2]); + ROCM_TRANSFORM_CHECK(rocm::type_identity, volatile[2], volatile[2]); + ROCM_TRANSFORM_CHECK(rocm::type_identity, const volatile[2], const volatile[2]); + ROCM_TRANSFORM_CHECK(rocm::type_identity, [2], [2]); + ROCM_TRANSFORM_CHECK(rocm::type_identity, const*, const*); + ROCM_TRANSFORM_CHECK(rocm::type_identity, const* volatile, const* volatile); + ROCM_TRANSFORM_CHECK(rocm::type_identity, (), ()); + ROCM_TRANSFORM_CHECK(rocm::type_identity, (int), (int)); + ROCM_TRANSFORM_CHECK(rocm::type_identity, (*const)(), (*const)()); +} + +TEST_CASE(void_t) +{ + ROCM_CHECK_TYPE(rocm::void_t, void); + ROCM_CHECK_TYPE(rocm::void_t, void); + ROCM_CHECK_TYPE(rocm::void_t, void); + ROCM_CHECK_TYPE(rocm::void_t, void); + ROCM_CHECK_TYPE(rocm::void_t, void); + ROCM_CHECK_TYPE(rocm::void_t, void); + ROCM_CHECK_TYPE(rocm::void_t, void); + + ROCM_CHECK_TYPE(rocm::void_t<>, void); + ROCM_CHECK_TYPE(rocm::void_t, void); +} diff --git a/test/gpu/kernels/rocm/type_traits_categories.cpp b/test/gpu/kernels/rocm/type_traits_categories.cpp new file mode 100644 index 00000000000..bc28c708362 --- /dev/null +++ b/test/gpu/kernels/rocm/type_traits_categories.cpp @@ -0,0 +1,603 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2025-2026 Advanced Micro Devices, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include +#include + +namespace tt_cat { + +enum test_enum +{ + val_a, + val_b +}; + +enum class scoped_enum +{ + x, + y +}; + +struct simple_class +{ + int x; +}; + +union simple_union +{ + int x; + double y; +}; + +struct udt +{ + int member_var; + void member_func(); + int member_func_int(int); + int member_func_float(int, float); +}; + +struct incomplete_type; + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wredundant-parens" +using func_ptr = void (*)(); +using func_ptr_i = int (*)(int); +using mfp_void = void (udt::*)(); +using mfp_int = int (udt::*)(); +using mfp_int_arg = int (udt::*)(int); +using mfp_int_flt = int (udt::*)(int, float); +using mop = int(udt::*); +using cmfp = int (udt::*)(int) const; +#pragma clang diagnostic pop + +using func_t0 = void(); +using func_t1 = void(int); +using func_t2 = void(int&, double); +using func_t3 = void(int&, bool, int, int); +using func_t4 = void(int, bool, int*, int[], int, int, int, int, int); + +} // namespace tt_cat + +// ---------- primary type categories ---------- + +TEST_CASE(is_integral) +{ + EXPECT(rocm::is_integral{}); + EXPECT(rocm::is_integral{}); + EXPECT(rocm::is_integral{}); + EXPECT(rocm::is_integral{}); + EXPECT(rocm::is_integral{}); + EXPECT(rocm::is_integral{}); + EXPECT(rocm::is_integral{}); + EXPECT(rocm::is_integral{}); + EXPECT(rocm::is_integral{}); + EXPECT(rocm::is_integral{}); + EXPECT(rocm::is_integral{}); + EXPECT(rocm::is_integral{}); + EXPECT(rocm::is_integral{}); + EXPECT(rocm::is_integral{}); + EXPECT(rocm::is_integral{}); + EXPECT(rocm::is_integral{}); + EXPECT(rocm::is_integral{}); + EXPECT(rocm::is_integral{}); + EXPECT(rocm::is_integral{}); + + EXPECT(not rocm::is_integral{}); + EXPECT(not rocm::is_integral{}); + EXPECT(not rocm::is_integral{}); + EXPECT(not rocm::is_integral{}); + EXPECT(not rocm::is_integral{}); + EXPECT(not rocm::is_integral{}); + EXPECT(not rocm::is_integral{}); + EXPECT(not rocm::is_integral{}); + EXPECT(not rocm::is_integral{}); + EXPECT(not rocm::is_integral{}); + EXPECT(not rocm::is_integral{}); + EXPECT(not rocm::is_integral{}); + EXPECT(not rocm::is_integral{}); + EXPECT(not rocm::is_integral{}); +} + +TEST_CASE(is_floating_point) +{ + EXPECT(rocm::is_floating_point{}); + EXPECT(rocm::is_floating_point{}); + EXPECT(rocm::is_floating_point{}); + EXPECT(rocm::is_floating_point{}); + EXPECT(rocm::is_floating_point{}); + EXPECT(rocm::is_floating_point{}); + EXPECT(rocm::is_floating_point{}); + EXPECT(rocm::is_floating_point{}); + EXPECT(rocm::is_floating_point{}); + EXPECT(rocm::is_floating_point{}); + EXPECT(rocm::is_floating_point{}); + EXPECT(rocm::is_floating_point{}); + + EXPECT(not rocm::is_floating_point{}); + EXPECT(not rocm::is_floating_point{}); + EXPECT(not rocm::is_floating_point{}); + EXPECT(not rocm::is_floating_point{}); + EXPECT(not rocm::is_floating_point{}); + EXPECT(not rocm::is_floating_point{}); + EXPECT(not rocm::is_floating_point{}); + EXPECT(not rocm::is_floating_point{}); + EXPECT(not rocm::is_floating_point{}); + EXPECT(not rocm::is_floating_point{}); +} + +TEST_CASE(is_array) +{ + EXPECT(rocm::is_array{}); + EXPECT(rocm::is_array{}); + EXPECT(rocm::is_array{}); + EXPECT(rocm::is_array{}); + EXPECT(rocm::is_array{}); + EXPECT(rocm::is_array{}); + EXPECT(rocm::is_array{}); + EXPECT(rocm::is_array{}); + EXPECT(rocm::is_array{}); + + EXPECT(not rocm::is_array{}); + EXPECT(not rocm::is_array{}); + EXPECT(not rocm::is_array{}); + EXPECT(not rocm::is_array{}); + EXPECT(not rocm::is_array{}); + EXPECT(not rocm::is_array{}); + EXPECT(not rocm::is_array{}); + EXPECT(not rocm::is_array{}); + EXPECT(not rocm::is_array{}); + EXPECT(not rocm::is_array{}); + EXPECT(not rocm::is_array{}); +} + +TEST_CASE(is_class) +{ + EXPECT(rocm::is_class{}); + EXPECT(rocm::is_class{}); + EXPECT(rocm::is_class{}); + EXPECT(rocm::is_class{}); + EXPECT(rocm::is_class{}); + + EXPECT(not rocm::is_class{}); + EXPECT(not rocm::is_class{}); + EXPECT(not rocm::is_class{}); + EXPECT(not rocm::is_class{}); + EXPECT(not rocm::is_class{}); + EXPECT(not rocm::is_class{}); + EXPECT(not rocm::is_class{}); + EXPECT(not rocm::is_class{}); + EXPECT(not rocm::is_class{}); + EXPECT(not rocm::is_class{}); + EXPECT(not rocm::is_class{}); + EXPECT(not rocm::is_class{}); + EXPECT(not rocm::is_class{}); + EXPECT(not rocm::is_class{}); +} + +TEST_CASE(is_enum) +{ + EXPECT(rocm::is_enum{}); + EXPECT(rocm::is_enum{}); + EXPECT(rocm::is_enum{}); + EXPECT(rocm::is_enum{}); + EXPECT(rocm::is_enum{}); + EXPECT(rocm::is_enum{}); + + EXPECT(not rocm::is_enum{}); + EXPECT(not rocm::is_enum{}); + EXPECT(not rocm::is_enum{}); + EXPECT(not rocm::is_enum{}); + EXPECT(not rocm::is_enum{}); + EXPECT(not rocm::is_enum{}); + EXPECT(not rocm::is_enum{}); + EXPECT(not rocm::is_enum{}); + EXPECT(not rocm::is_enum{}); + EXPECT(not rocm::is_enum{}); +} + +TEST_CASE(is_union) +{ + EXPECT(rocm::is_union{}); + EXPECT(rocm::is_union{}); + EXPECT(rocm::is_union{}); + EXPECT(rocm::is_union{}); + + EXPECT(not rocm::is_union{}); + EXPECT(not rocm::is_union{}); + EXPECT(not rocm::is_union{}); + EXPECT(not rocm::is_union{}); + EXPECT(not rocm::is_union{}); + EXPECT(not rocm::is_union{}); + EXPECT(not rocm::is_union{}); + EXPECT(not rocm::is_union{}); +} + +TEST_CASE(is_function) +{ + EXPECT(rocm::is_function{}); + EXPECT(rocm::is_function{}); + EXPECT(rocm::is_function{}); + EXPECT(rocm::is_function{}); + EXPECT(rocm::is_function{}); + + EXPECT(not rocm::is_function{}); + EXPECT(not rocm::is_function{}); + EXPECT(not rocm::is_function{}); + EXPECT(not rocm::is_function{}); + EXPECT(not rocm::is_function{}); + EXPECT(not rocm::is_function{}); + EXPECT(not rocm::is_function{}); + EXPECT(not rocm::is_function{}); + EXPECT(not rocm::is_function{}); + EXPECT(not rocm::is_function{}); + EXPECT(not rocm::is_function{}); +} + +TEST_CASE(is_lvalue_reference) +{ + EXPECT(rocm::is_lvalue_reference{}); + EXPECT(rocm::is_lvalue_reference{}); + EXPECT(rocm::is_lvalue_reference{}); + EXPECT(rocm::is_lvalue_reference{}); + EXPECT(rocm::is_lvalue_reference{}); + EXPECT(rocm::is_lvalue_reference{}); + + EXPECT(not rocm::is_lvalue_reference{}); + EXPECT(not rocm::is_lvalue_reference{}); + EXPECT(not rocm::is_lvalue_reference{}); + EXPECT(not rocm::is_lvalue_reference{}); + EXPECT(not rocm::is_lvalue_reference{}); + EXPECT(not rocm::is_lvalue_reference{}); + EXPECT(not rocm::is_lvalue_reference{}); +} + +TEST_CASE(is_rvalue_reference) +{ + EXPECT(rocm::is_rvalue_reference{}); + EXPECT(rocm::is_rvalue_reference{}); + EXPECT(rocm::is_rvalue_reference{}); + EXPECT(rocm::is_rvalue_reference{}); + EXPECT(rocm::is_rvalue_reference{}); + EXPECT(rocm::is_rvalue_reference{}); + + EXPECT(not rocm::is_rvalue_reference{}); + EXPECT(not rocm::is_rvalue_reference{}); + EXPECT(not rocm::is_rvalue_reference{}); + EXPECT(not rocm::is_rvalue_reference{}); + EXPECT(not rocm::is_rvalue_reference{}); + EXPECT(not rocm::is_rvalue_reference{}); +} + +TEST_CASE(is_member_object_pointer) +{ + EXPECT(rocm::is_member_object_pointer{}); + EXPECT(rocm::is_member_object_pointer{}); + EXPECT(rocm::is_member_object_pointer{}); + + EXPECT(not rocm::is_member_object_pointer{}); + EXPECT(not rocm::is_member_object_pointer{}); + EXPECT(not rocm::is_member_object_pointer{}); + EXPECT(not rocm::is_member_object_pointer{}); + EXPECT(not rocm::is_member_object_pointer{}); + EXPECT(not rocm::is_member_object_pointer{}); + EXPECT(not rocm::is_member_object_pointer{}); + EXPECT(not rocm::is_member_object_pointer{}); +} + +TEST_CASE(is_member_function_pointer) +{ + EXPECT(rocm::is_member_function_pointer{}); + EXPECT(rocm::is_member_function_pointer{}); + EXPECT(rocm::is_member_function_pointer{}); + EXPECT(rocm::is_member_function_pointer{}); + EXPECT(rocm::is_member_function_pointer{}); + EXPECT(rocm::is_member_function_pointer{}); + + EXPECT(not rocm::is_member_function_pointer{}); + EXPECT(not rocm::is_member_function_pointer{}); + EXPECT(not rocm::is_member_function_pointer{}); + EXPECT(not rocm::is_member_function_pointer{}); + EXPECT(not rocm::is_member_function_pointer{}); + EXPECT(not rocm::is_member_function_pointer{}); + EXPECT(not rocm::is_member_function_pointer{}); +} + +TEST_CASE(is_pointer) +{ + EXPECT(rocm::is_pointer{}); + EXPECT(rocm::is_pointer{}); + EXPECT(rocm::is_pointer{}); + EXPECT(rocm::is_pointer{}); + EXPECT(rocm::is_pointer{}); + EXPECT(rocm::is_pointer{}); + // top-level cv-qualified pointers are still pointers + EXPECT(rocm::is_pointer{}); + EXPECT(rocm::is_pointer{}); + EXPECT(rocm::is_pointer{}); + // function pointers + EXPECT(rocm::is_pointer{}); + EXPECT(rocm::is_pointer{}); + EXPECT(rocm::is_pointer{}); + // void pointers + EXPECT(rocm::is_pointer{}); + EXPECT(rocm::is_pointer{}); + + EXPECT(not rocm::is_pointer{}); + EXPECT(not rocm::is_pointer{}); + EXPECT(not rocm::is_pointer{}); + EXPECT(not rocm::is_pointer{}); + EXPECT(not rocm::is_pointer{}); + EXPECT(not rocm::is_pointer{}); + EXPECT(not rocm::is_pointer{}); + EXPECT(not rocm::is_pointer{}); + EXPECT(not rocm::is_pointer{}); + // member function pointers are not pointers (3.9.2p3) + EXPECT(not rocm::is_pointer{}); + EXPECT(not rocm::is_pointer{}); + EXPECT(not rocm::is_pointer{}); + EXPECT(not rocm::is_pointer{}); + // member object pointer is not a pointer + EXPECT(not rocm::is_pointer{}); + // function types are not pointers + EXPECT(not rocm::is_pointer{}); + EXPECT(not rocm::is_pointer{}); + EXPECT(not rocm::is_pointer{}); + EXPECT(not rocm::is_pointer{}); + EXPECT(not rocm::is_pointer{}); +} + +TEST_CASE(is_null_pointer) +{ + EXPECT(rocm::is_null_pointer{}); + EXPECT(rocm::is_null_pointer{}); + EXPECT(rocm::is_null_pointer{}); + EXPECT(rocm::is_null_pointer{}); + + EXPECT(not rocm::is_null_pointer{}); + EXPECT(not rocm::is_null_pointer{}); + EXPECT(not rocm::is_null_pointer{}); + EXPECT(not rocm::is_null_pointer{}); + EXPECT(not rocm::is_null_pointer{}); + EXPECT(not rocm::is_null_pointer{}); + EXPECT(not rocm::is_null_pointer{}); + EXPECT(not rocm::is_null_pointer{}); + EXPECT(not rocm::is_null_pointer{}); + EXPECT(not rocm::is_null_pointer{}); + EXPECT(not rocm::is_null_pointer{}); + EXPECT(not rocm::is_null_pointer{}); + EXPECT(not rocm::is_null_pointer{}); + EXPECT(not rocm::is_null_pointer{}); +} + +// ---------- composite type categories ---------- + +TEST_CASE(is_reference) +{ + EXPECT(rocm::is_reference{}); + EXPECT(rocm::is_reference{}); + EXPECT(rocm::is_reference{}); + EXPECT(rocm::is_reference{}); + EXPECT(rocm::is_reference{}); + EXPECT(rocm::is_reference{}); + EXPECT(rocm::is_reference{}); + EXPECT(rocm::is_reference{}); + + EXPECT(not rocm::is_reference{}); + EXPECT(not rocm::is_reference{}); + EXPECT(not rocm::is_reference{}); + EXPECT(not rocm::is_reference{}); + EXPECT(not rocm::is_reference{}); + EXPECT(not rocm::is_reference{}); +} + +TEST_CASE(is_member_pointer) +{ + EXPECT(rocm::is_member_pointer{}); + EXPECT(rocm::is_member_pointer{}); + EXPECT(rocm::is_member_pointer{}); + EXPECT(rocm::is_member_pointer{}); + EXPECT(rocm::is_member_pointer{}); + EXPECT(rocm::is_member_pointer{}); + + EXPECT(not rocm::is_member_pointer{}); + EXPECT(not rocm::is_member_pointer{}); + EXPECT(not rocm::is_member_pointer{}); + EXPECT(not rocm::is_member_pointer{}); + EXPECT(not rocm::is_member_pointer{}); + EXPECT(not rocm::is_member_pointer{}); +} + +TEST_CASE(is_arithmetic) +{ + // integral types + EXPECT(rocm::is_arithmetic{}); + EXPECT(rocm::is_arithmetic{}); + EXPECT(rocm::is_arithmetic{}); + EXPECT(rocm::is_arithmetic{}); + + EXPECT(rocm::is_arithmetic{}); + EXPECT(rocm::is_arithmetic{}); + EXPECT(rocm::is_arithmetic{}); + EXPECT(rocm::is_arithmetic{}); + EXPECT(rocm::is_arithmetic{}); + EXPECT(rocm::is_arithmetic{}); + EXPECT(rocm::is_arithmetic{}); + EXPECT(rocm::is_arithmetic{}); + EXPECT(rocm::is_arithmetic{}); + EXPECT(rocm::is_arithmetic{}); + EXPECT(rocm::is_arithmetic{}); + EXPECT(rocm::is_arithmetic{}); + EXPECT(rocm::is_arithmetic{}); + EXPECT(rocm::is_arithmetic{}); + + EXPECT(rocm::is_arithmetic{}); + EXPECT(rocm::is_arithmetic{}); + EXPECT(rocm::is_arithmetic{}); + EXPECT(rocm::is_arithmetic{}); + EXPECT(rocm::is_arithmetic{}); + EXPECT(rocm::is_arithmetic{}); + EXPECT(rocm::is_arithmetic{}); + EXPECT(rocm::is_arithmetic{}); + + EXPECT(rocm::is_arithmetic{}); + EXPECT(rocm::is_arithmetic{}); + EXPECT(rocm::is_arithmetic{}); + EXPECT(rocm::is_arithmetic{}); + EXPECT(rocm::is_arithmetic{}); + EXPECT(rocm::is_arithmetic{}); + EXPECT(rocm::is_arithmetic{}); + EXPECT(rocm::is_arithmetic{}); + + EXPECT(rocm::is_arithmetic{}); + EXPECT(rocm::is_arithmetic{}); + EXPECT(rocm::is_arithmetic{}); + EXPECT(rocm::is_arithmetic{}); + EXPECT(rocm::is_arithmetic{}); + EXPECT(rocm::is_arithmetic{}); + EXPECT(rocm::is_arithmetic{}); + EXPECT(rocm::is_arithmetic{}); + + EXPECT(rocm::is_arithmetic{}); + EXPECT(rocm::is_arithmetic{}); + EXPECT(rocm::is_arithmetic{}); + EXPECT(rocm::is_arithmetic{}); + EXPECT(rocm::is_arithmetic{}); + EXPECT(rocm::is_arithmetic{}); + EXPECT(rocm::is_arithmetic{}); + EXPECT(rocm::is_arithmetic{}); + + // floating-point types + EXPECT(rocm::is_arithmetic{}); + EXPECT(rocm::is_arithmetic{}); + EXPECT(rocm::is_arithmetic{}); + EXPECT(rocm::is_arithmetic{}); + + EXPECT(rocm::is_arithmetic{}); + EXPECT(rocm::is_arithmetic{}); + EXPECT(rocm::is_arithmetic{}); + EXPECT(rocm::is_arithmetic{}); + + EXPECT(rocm::is_arithmetic{}); + EXPECT(rocm::is_arithmetic{}); + EXPECT(rocm::is_arithmetic{}); + EXPECT(rocm::is_arithmetic{}); + + // non-arithmetic types + EXPECT(not rocm::is_arithmetic{}); + EXPECT(not rocm::is_arithmetic{}); + EXPECT(not rocm::is_arithmetic{}); + EXPECT(not rocm::is_arithmetic{}); + EXPECT(not rocm::is_arithmetic{}); + EXPECT(not rocm::is_arithmetic{}); + EXPECT(not rocm::is_arithmetic{}); + EXPECT(not rocm::is_arithmetic{}); + EXPECT(not rocm::is_arithmetic{}); + EXPECT(not rocm::is_arithmetic{}); + EXPECT(not rocm::is_arithmetic{}); + EXPECT(not rocm::is_arithmetic{}); + EXPECT(not rocm::is_arithmetic{}); + EXPECT(not rocm::is_arithmetic{}); + EXPECT(not rocm::is_arithmetic{}); + EXPECT(not rocm::is_arithmetic{}); + EXPECT(not rocm::is_arithmetic{}); + EXPECT(not rocm::is_arithmetic{}); + EXPECT(not rocm::is_arithmetic{}); + EXPECT(not rocm::is_arithmetic{}); +} + +TEST_CASE(is_fundamental) +{ + EXPECT(rocm::is_fundamental{}); + EXPECT(rocm::is_fundamental{}); + EXPECT(rocm::is_fundamental{}); + EXPECT(rocm::is_fundamental{}); + EXPECT(rocm::is_fundamental{}); + EXPECT(rocm::is_fundamental{}); + EXPECT(rocm::is_fundamental{}); + EXPECT(rocm::is_fundamental{}); + EXPECT(rocm::is_fundamental{}); + EXPECT(rocm::is_fundamental{}); + EXPECT(rocm::is_fundamental{}); + EXPECT(rocm::is_fundamental{}); + EXPECT(rocm::is_fundamental{}); + + EXPECT(not rocm::is_fundamental{}); + EXPECT(not rocm::is_fundamental{}); + EXPECT(not rocm::is_fundamental{}); + EXPECT(not rocm::is_fundamental{}); + EXPECT(not rocm::is_fundamental{}); + EXPECT(not rocm::is_fundamental{}); + EXPECT(not rocm::is_fundamental{}); + EXPECT(not rocm::is_fundamental{}); + EXPECT(not rocm::is_fundamental{}); + EXPECT(not rocm::is_fundamental{}); +} + +TEST_CASE(is_compound) +{ + EXPECT(rocm::is_compound{}); + EXPECT(rocm::is_compound{}); + EXPECT(rocm::is_compound{}); + EXPECT(rocm::is_compound{}); + EXPECT(rocm::is_compound{}); + EXPECT(rocm::is_compound{}); + EXPECT(rocm::is_compound{}); + EXPECT(rocm::is_compound{}); + EXPECT(rocm::is_compound{}); + EXPECT(rocm::is_compound{}); + EXPECT(rocm::is_compound{}); + EXPECT(rocm::is_compound{}); + + EXPECT(not rocm::is_compound{}); + EXPECT(not rocm::is_compound{}); + EXPECT(not rocm::is_compound{}); + EXPECT(not rocm::is_compound{}); + EXPECT(not rocm::is_compound{}); + EXPECT(not rocm::is_compound{}); + EXPECT(not rocm::is_compound{}); +} + +TEST_CASE(is_object) +{ + EXPECT(rocm::is_object{}); + EXPECT(rocm::is_object{}); + EXPECT(rocm::is_object{}); + EXPECT(rocm::is_object{}); + EXPECT(rocm::is_object{}); + EXPECT(rocm::is_object{}); + EXPECT(rocm::is_object{}); + EXPECT(rocm::is_object{}); + EXPECT(rocm::is_object{}); + EXPECT(rocm::is_object{}); + EXPECT(rocm::is_object{}); + + EXPECT(not rocm::is_object{}); + EXPECT(not rocm::is_object{}); + EXPECT(not rocm::is_object{}); + EXPECT(not rocm::is_object{}); + EXPECT(not rocm::is_object{}); + EXPECT(not rocm::is_object{}); +} diff --git a/test/gpu/kernels/rocm/type_traits_properties.cpp b/test/gpu/kernels/rocm/type_traits_properties.cpp new file mode 100644 index 00000000000..d463afef568 --- /dev/null +++ b/test/gpu/kernels/rocm/type_traits_properties.cpp @@ -0,0 +1,423 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2025-2026 Advanced Micro Devices, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include +#include + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wnon-virtual-dtor" + +namespace tt_prop { + +struct empty_class +{ +}; + +struct non_empty_class +{ + int x; +}; + +struct pod_class +{ + int x; + double y; +}; + +union test_union +{ + int x; + double y; +}; + +struct abstract_base +{ + virtual void foo() = 0; +}; + +struct abstract_derived : abstract_base +{ + virtual void bar() = 0; +}; + +struct concrete_override : abstract_base +{ + void foo() override {} +}; + +struct still_abstract : abstract_base +{ + virtual void bar() = 0; + void foo() override {} +}; + +struct polymorphic_class +{ + virtual void foo(); +}; + +struct polymorphic_derived : polymorphic_class +{ +}; + +struct non_polymorphic +{ + void foo(); +}; + +struct final_class final +{ +}; + +struct final_derived final : non_polymorphic +{ +}; + +struct non_aggregate +{ + non_aggregate(int); +}; + +struct trivial_class +{ +}; + +struct non_trivial +{ + non_trivial(); + ~non_trivial(); +}; + +struct non_trivially_copyable +{ + non_trivially_copyable(const non_trivially_copyable&); +}; + +struct standard_layout_class +{ + int x; + int y; +}; + +struct non_standard_layout +{ + virtual void f(); + int x; +}; + +enum test_enum +{ + val_a, + val_b +}; + +using func_t = void(); +using func_ptr = void (*)(); + +} // namespace tt_prop + +#pragma clang diagnostic pop + +TEST_CASE(is_const) +{ + EXPECT(rocm::is_const{}); + EXPECT(rocm::is_const{}); + EXPECT(rocm::is_const{}); + EXPECT(rocm::is_const{}); + EXPECT(rocm::is_const{}); + EXPECT(rocm::is_const{}); + EXPECT(rocm::is_const{}); + + EXPECT(not rocm::is_const{}); + EXPECT(not rocm::is_const{}); + EXPECT(not rocm::is_const{}); + EXPECT(not rocm::is_const{}); + EXPECT(not rocm::is_const{}); + EXPECT(not rocm::is_const{}); + EXPECT(not rocm::is_const{}); + EXPECT(not rocm::is_const{}); + EXPECT(not rocm::is_const{}); + EXPECT(not rocm::is_const{}); +} + +TEST_CASE(is_volatile) +{ + EXPECT(rocm::is_volatile{}); + EXPECT(rocm::is_volatile{}); + EXPECT(rocm::is_volatile{}); + EXPECT(rocm::is_volatile{}); + EXPECT(rocm::is_volatile{}); + EXPECT(rocm::is_volatile{}); + EXPECT(rocm::is_volatile{}); + + EXPECT(not rocm::is_volatile{}); + EXPECT(not rocm::is_volatile{}); + EXPECT(not rocm::is_volatile{}); + EXPECT(not rocm::is_volatile{}); + EXPECT(not rocm::is_volatile{}); + EXPECT(not rocm::is_volatile{}); + EXPECT(not rocm::is_volatile{}); + EXPECT(not rocm::is_volatile{}); + EXPECT(not rocm::is_volatile{}); +} + +TEST_CASE(is_abstract) +{ + EXPECT(rocm::is_abstract{}); + EXPECT(rocm::is_abstract{}); + EXPECT(rocm::is_abstract{}); + EXPECT(rocm::is_abstract{}); + EXPECT(rocm::is_abstract{}); + EXPECT(rocm::is_abstract{}); + + EXPECT(not rocm::is_abstract{}); + EXPECT(not rocm::is_abstract{}); + EXPECT(not rocm::is_abstract{}); + EXPECT(not rocm::is_abstract{}); + EXPECT(not rocm::is_abstract{}); + EXPECT(not rocm::is_abstract{}); + EXPECT(not rocm::is_abstract{}); + EXPECT(not rocm::is_abstract{}); + EXPECT(not rocm::is_abstract{}); + EXPECT(not rocm::is_abstract{}); + EXPECT(not rocm::is_abstract{}); + EXPECT(not rocm::is_abstract{}); + EXPECT(not rocm::is_abstract{}); +} + +TEST_CASE(is_aggregate) +{ + EXPECT(rocm::is_aggregate{}); + EXPECT(rocm::is_aggregate{}); + EXPECT(rocm::is_aggregate{}); + EXPECT(rocm::is_aggregate{}); + EXPECT(rocm::is_aggregate{}); + EXPECT(rocm::is_aggregate{}); + EXPECT(rocm::is_aggregate{}); + EXPECT(rocm::is_aggregate{}); + + EXPECT(not rocm::is_aggregate{}); + EXPECT(not rocm::is_aggregate{}); + EXPECT(not rocm::is_aggregate{}); + EXPECT(not rocm::is_aggregate{}); + EXPECT(not rocm::is_aggregate{}); + EXPECT(not rocm::is_aggregate{}); + EXPECT(not rocm::is_aggregate{}); +} + +TEST_CASE(is_empty) +{ + EXPECT(rocm::is_empty{}); + EXPECT(rocm::is_empty{}); + EXPECT(rocm::is_empty{}); + EXPECT(rocm::is_empty{}); + + EXPECT(not rocm::is_empty{}); + EXPECT(not rocm::is_empty{}); + EXPECT(not rocm::is_empty{}); + EXPECT(not rocm::is_empty{}); + EXPECT(not rocm::is_empty{}); + EXPECT(not rocm::is_empty{}); + EXPECT(not rocm::is_empty{}); + EXPECT(not rocm::is_empty{}); + EXPECT(not rocm::is_empty{}); + EXPECT(not rocm::is_empty{}); +} + +TEST_CASE(is_final) +{ + EXPECT(rocm::is_final{}); + EXPECT(rocm::is_final{}); + EXPECT(rocm::is_final{}); + EXPECT(rocm::is_final{}); + EXPECT(rocm::is_final{}); + + EXPECT(not rocm::is_final{}); + EXPECT(not rocm::is_final{}); + EXPECT(not rocm::is_final{}); + EXPECT(not rocm::is_final{}); + EXPECT(not rocm::is_final{}); + EXPECT(not rocm::is_final{}); +} + +TEST_CASE(is_polymorphic) +{ + EXPECT(rocm::is_polymorphic{}); + EXPECT(rocm::is_polymorphic{}); + EXPECT(rocm::is_polymorphic{}); + EXPECT(rocm::is_polymorphic{}); + EXPECT(rocm::is_polymorphic{}); + EXPECT(rocm::is_polymorphic{}); + EXPECT(rocm::is_polymorphic{}); + EXPECT(rocm::is_polymorphic{}); + + EXPECT(not rocm::is_polymorphic{}); + EXPECT(not rocm::is_polymorphic{}); + EXPECT(not rocm::is_polymorphic{}); + EXPECT(not rocm::is_polymorphic{}); + EXPECT(not rocm::is_polymorphic{}); + EXPECT(not rocm::is_polymorphic{}); + EXPECT(not rocm::is_polymorphic{}); + EXPECT(not rocm::is_polymorphic{}); + EXPECT(not rocm::is_polymorphic{}); + EXPECT(not rocm::is_polymorphic{}); +} + +TEST_CASE(is_standard_layout) +{ + EXPECT(rocm::is_standard_layout{}); + EXPECT(rocm::is_standard_layout{}); + EXPECT(rocm::is_standard_layout{}); + EXPECT(rocm::is_standard_layout{}); + EXPECT(rocm::is_standard_layout{}); + EXPECT(rocm::is_standard_layout{}); + EXPECT(rocm::is_standard_layout{}); + EXPECT(rocm::is_standard_layout{}); + EXPECT(rocm::is_standard_layout{}); + EXPECT(rocm::is_standard_layout{}); + EXPECT(rocm::is_standard_layout{}); + + EXPECT(not rocm::is_standard_layout{}); + EXPECT(not rocm::is_standard_layout{}); + EXPECT(not rocm::is_standard_layout{}); +} + +TEST_CASE(is_trivial) +{ + EXPECT(rocm::is_trivial{}); + EXPECT(rocm::is_trivial{}); + EXPECT(rocm::is_trivial{}); + EXPECT(rocm::is_trivial{}); + EXPECT(rocm::is_trivial{}); + EXPECT(rocm::is_trivial{}); + EXPECT(rocm::is_trivial{}); + EXPECT(rocm::is_trivial{}); + EXPECT(rocm::is_trivial{}); + EXPECT(rocm::is_trivial{}); + + EXPECT(not rocm::is_trivial{}); + EXPECT(not rocm::is_trivial{}); + EXPECT(not rocm::is_trivial{}); + EXPECT(not rocm::is_trivial{}); +} + +TEST_CASE(is_trivially_copyable) +{ + EXPECT(rocm::is_trivially_copyable{}); + EXPECT(rocm::is_trivially_copyable{}); + EXPECT(rocm::is_trivially_copyable{}); + EXPECT(rocm::is_trivially_copyable{}); + EXPECT(rocm::is_trivially_copyable{}); + EXPECT(rocm::is_trivially_copyable{}); + EXPECT(rocm::is_trivially_copyable{}); + EXPECT(rocm::is_trivially_copyable{}); + EXPECT(rocm::is_trivially_copyable{}); + + EXPECT(not rocm::is_trivially_copyable{}); + EXPECT(not rocm::is_trivially_copyable{}); + EXPECT(not rocm::is_trivially_copyable{}); + EXPECT(not rocm::is_trivially_copyable{}); +} + +TEST_CASE(is_trivially_destructible) +{ + EXPECT(rocm::is_trivially_destructible{}); + EXPECT(rocm::is_trivially_destructible{}); + EXPECT(rocm::is_trivially_destructible{}); + EXPECT(rocm::is_trivially_destructible{}); + EXPECT(rocm::is_trivially_destructible{}); + EXPECT(rocm::is_trivially_destructible{}); + EXPECT(rocm::is_trivially_destructible{}); + EXPECT(rocm::is_trivially_destructible{}); + EXPECT(rocm::is_trivially_destructible{}); + EXPECT(rocm::is_trivially_destructible{}); + + EXPECT(not rocm::is_trivially_destructible{}); +} + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + +TEST_CASE(is_pod) +{ + EXPECT(rocm::is_pod{}); + EXPECT(rocm::is_pod{}); + EXPECT(rocm::is_pod{}); + EXPECT(rocm::is_pod{}); + EXPECT(rocm::is_pod{}); + EXPECT(rocm::is_pod{}); + EXPECT(rocm::is_pod{}); + EXPECT(rocm::is_pod{}); + EXPECT(rocm::is_pod{}); + EXPECT(rocm::is_pod{}); + + EXPECT(not rocm::is_pod{}); + EXPECT(not rocm::is_pod{}); + EXPECT(not rocm::is_pod{}); + EXPECT(not rocm::is_pod{}); + EXPECT(not rocm::is_pod{}); +} + +TEST_CASE(is_literal_type) +{ + EXPECT(rocm::is_literal_type{}); + EXPECT(rocm::is_literal_type{}); + EXPECT(rocm::is_literal_type{}); + EXPECT(rocm::is_literal_type{}); + EXPECT(rocm::is_literal_type{}); + EXPECT(rocm::is_literal_type{}); + EXPECT(rocm::is_literal_type{}); + EXPECT(rocm::is_literal_type{}); + EXPECT(rocm::is_literal_type{}); + EXPECT(rocm::is_literal_type{}); + + EXPECT(not rocm::is_literal_type{}); +} + +#pragma clang diagnostic pop + +TEST_CASE(is_unsigned) +{ + EXPECT(rocm::is_unsigned{}); + EXPECT(rocm::is_unsigned{}); + EXPECT(rocm::is_unsigned{}); + EXPECT(rocm::is_unsigned{}); + EXPECT(rocm::is_unsigned{}); + EXPECT(rocm::is_unsigned{}); + EXPECT(rocm::is_unsigned{}); + EXPECT(rocm::is_unsigned{}); + EXPECT(rocm::is_unsigned{}); + + EXPECT(not rocm::is_unsigned{}); + EXPECT(not rocm::is_unsigned{}); + EXPECT(not rocm::is_unsigned{}); + EXPECT(not rocm::is_unsigned{}); + EXPECT(not rocm::is_unsigned{}); + EXPECT(not rocm::is_unsigned{}); + EXPECT(not rocm::is_unsigned{}); + EXPECT(not rocm::is_unsigned{}); + EXPECT(not rocm::is_unsigned{}); + EXPECT(not rocm::is_unsigned{}); +} diff --git a/test/gpu/kernels/rocm/type_traits_relationships.cpp b/test/gpu/kernels/rocm/type_traits_relationships.cpp new file mode 100644 index 00000000000..6d7420583d5 --- /dev/null +++ b/test/gpu/kernels/rocm/type_traits_relationships.cpp @@ -0,0 +1,312 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2025-2026 Advanced Micro Devices, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include +#include + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wnon-virtual-dtor" + +namespace tt_rel { + +struct base +{ +}; + +struct derived : base +{ +}; + +struct derived2 : base +{ +}; + +struct multi_derived : derived, derived2 +{ +}; + +struct private_derived : private base +{ +}; + +struct unrelated +{ +}; + +struct virtual_base +{ + virtual void foo(); +}; + +struct virtual_derived : virtual_base +{ +}; + +struct convertible_to_int +{ + operator int(); +}; + +struct convertible_from_int +{ + convertible_from_int(int); +}; + +struct trivial_class +{ +}; + +struct non_trivial_copy +{ + non_trivial_copy() = default; + non_trivial_copy(const non_trivial_copy&); +}; + +struct non_trivial_assign +{ + non_trivial_assign& operator=(const non_trivial_assign&); +}; + +struct nothrow_default +{ + nothrow_default() noexcept; +}; + +struct throwing_default +{ + throwing_default() noexcept(false); +}; + +struct nothrow_copy +{ + nothrow_copy() = default; + nothrow_copy(const nothrow_copy&) noexcept; +}; + +struct throwing_copy +{ + throwing_copy() = default; + throwing_copy(const throwing_copy&) noexcept(false); +}; + +struct nothrow_assign +{ + nothrow_assign& operator=(const nothrow_assign&) noexcept; +}; + +struct throwing_assign +{ + throwing_assign& operator=(const throwing_assign&) noexcept(false); +}; + +enum test_enum +{ + val_a, + val_b +}; + +using func_t = void(); + +} // namespace tt_rel + +#pragma clang diagnostic pop + +TEST_CASE(is_same) +{ + EXPECT(rocm::is_same{}); + EXPECT(rocm::is_same{}); + EXPECT(rocm::is_same{}); + EXPECT(rocm::is_same{}); + EXPECT(rocm::is_same{}); + EXPECT(rocm::is_same{}); + EXPECT(rocm::is_same{}); + EXPECT(rocm::is_same{}); + EXPECT(rocm::is_same{}); + EXPECT(rocm::is_same{}); + EXPECT(rocm::is_same{}); + + EXPECT(not rocm::is_same{}); + EXPECT(not rocm::is_same{}); + EXPECT(not rocm::is_same{}); + EXPECT(not rocm::is_same{}); + EXPECT(not rocm::is_same{}); + EXPECT(not rocm::is_same{}); + EXPECT(not rocm::is_same{}); + EXPECT(not rocm::is_same{}); + EXPECT(not rocm::is_same{}); + EXPECT(not rocm::is_same{}); +} + +TEST_CASE(is_base_of) +{ + EXPECT(rocm::is_base_of{}); + EXPECT(rocm::is_base_of{}); + EXPECT(rocm::is_base_of{}); + EXPECT(rocm::is_base_of{}); + EXPECT(rocm::is_base_of{}); + EXPECT(rocm::is_base_of{}); + EXPECT(rocm::is_base_of{}); + EXPECT(rocm::is_base_of{}); + EXPECT(rocm::is_base_of{}); + + EXPECT(not rocm::is_base_of{}); + EXPECT(not rocm::is_base_of{}); + EXPECT(not rocm::is_base_of{}); + EXPECT(not rocm::is_base_of{}); + EXPECT(not rocm::is_base_of{}); + EXPECT(not rocm::is_base_of{}); + EXPECT(not rocm::is_base_of{}); +} + +TEST_CASE(is_convertible) +{ + EXPECT(rocm::is_convertible{}); + EXPECT(rocm::is_convertible{}); + EXPECT(rocm::is_convertible{}); + EXPECT(rocm::is_convertible{}); + EXPECT(rocm::is_convertible{}); + EXPECT(rocm::is_convertible{}); + EXPECT(rocm::is_convertible{}); + EXPECT(rocm::is_convertible{}); + EXPECT(rocm::is_convertible{}); + EXPECT(rocm::is_convertible{}); + EXPECT(rocm::is_convertible{}); + EXPECT(rocm::is_convertible{}); + EXPECT(rocm::is_convertible{}); + + EXPECT(not rocm::is_convertible{}); + EXPECT(not rocm::is_convertible{}); + EXPECT(not rocm::is_convertible{}); + EXPECT(not rocm::is_convertible{}); + EXPECT(not rocm::is_convertible{}); + EXPECT(not rocm::is_convertible{}); + EXPECT(not rocm::is_convertible{}); + EXPECT(not rocm::is_convertible{}); + EXPECT(not rocm::is_convertible{}); + EXPECT(not rocm::is_convertible{}); +} + +TEST_CASE(is_assignable) +{ + EXPECT(rocm::is_assignable{}); + EXPECT(rocm::is_assignable{}); + EXPECT(rocm::is_assignable{}); + EXPECT(rocm::is_assignable{}); + EXPECT(rocm::is_assignable{}); + EXPECT(rocm::is_assignable{}); + EXPECT(rocm::is_assignable{}); + + EXPECT(not rocm::is_assignable{}); + EXPECT(not rocm::is_assignable{}); + EXPECT(not rocm::is_assignable{}); + EXPECT(not rocm::is_assignable{}); + EXPECT(not rocm::is_assignable{}); + EXPECT(not rocm::is_assignable{}); +} + +TEST_CASE(is_nothrow_assignable) +{ + EXPECT(rocm::is_nothrow_assignable{}); + EXPECT(rocm::is_nothrow_assignable{}); + EXPECT(rocm::is_nothrow_assignable{}); + EXPECT(rocm::is_nothrow_assignable{}); + EXPECT(rocm::is_nothrow_assignable{}); + + EXPECT(not rocm::is_nothrow_assignable{}); + EXPECT(not rocm::is_nothrow_assignable{}); + EXPECT(not rocm::is_nothrow_assignable{}); + EXPECT(not rocm::is_nothrow_assignable{}); +} + +TEST_CASE(is_trivially_assignable) +{ + EXPECT(rocm::is_trivially_assignable{}); + EXPECT(rocm::is_trivially_assignable{}); + EXPECT(rocm::is_trivially_assignable{}); + EXPECT(rocm::is_trivially_assignable{}); + + EXPECT(not rocm::is_trivially_assignable{}); + EXPECT(not rocm::is_trivially_assignable{}); + EXPECT(not rocm::is_trivially_assignable{}); + EXPECT(not rocm::is_trivially_assignable{}); +} + +TEST_CASE(is_constructible) +{ + EXPECT(rocm::is_constructible{}); + EXPECT(rocm::is_constructible{}); + EXPECT(rocm::is_constructible{}); + EXPECT(rocm::is_constructible{}); + EXPECT(rocm::is_constructible{}); + EXPECT(rocm::is_constructible{}); + EXPECT(rocm::is_constructible{}); + EXPECT(rocm::is_constructible{}); + EXPECT(rocm::is_constructible{}); + EXPECT(rocm::is_constructible{}); + + EXPECT(not rocm::is_constructible{}); + EXPECT(not rocm::is_constructible{}); + EXPECT(not rocm::is_constructible{}); + EXPECT(not rocm::is_constructible{}); + EXPECT(not rocm::is_constructible{}); +} + +TEST_CASE(is_nothrow_constructible) +{ + EXPECT(rocm::is_nothrow_constructible{}); + EXPECT(rocm::is_nothrow_constructible{}); + EXPECT(rocm::is_nothrow_constructible{}); + EXPECT(rocm::is_nothrow_constructible{}); + EXPECT(rocm::is_nothrow_constructible{}); + EXPECT(rocm::is_nothrow_constructible{}); + EXPECT(rocm::is_nothrow_constructible{}); + EXPECT(rocm::is_nothrow_constructible{}); + + EXPECT(not rocm::is_nothrow_constructible{}); + EXPECT( + not rocm::is_nothrow_constructible{}); + EXPECT(not rocm::is_nothrow_constructible{}); + EXPECT(not rocm::is_nothrow_constructible{}); +} + +TEST_CASE(is_trivially_constructible) +{ + EXPECT(rocm::is_trivially_constructible{}); + EXPECT(rocm::is_trivially_constructible{}); + EXPECT(rocm::is_trivially_constructible{}); + EXPECT(rocm::is_trivially_constructible{}); + EXPECT(rocm::is_trivially_constructible{}); + EXPECT(rocm::is_trivially_constructible{}); + EXPECT(rocm::is_trivially_constructible{}); + EXPECT(rocm::is_trivially_constructible{}); + + EXPECT(not rocm::is_trivially_constructible{}); + EXPECT(not rocm::is_trivially_constructible{}); + EXPECT(not rocm::is_trivially_constructible{}); + EXPECT(not rocm::is_trivially_constructible{}); +} diff --git a/test/gpu/kernels/rocm/utility/forward.cpp b/test/gpu/kernels/rocm/utility/forward.cpp new file mode 100644 index 00000000000..2788e32df3d --- /dev/null +++ b/test/gpu/kernels/rocm/utility/forward.cpp @@ -0,0 +1,160 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2025-2026 Advanced Micro Devices, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#include +#include +#include + +// ---- helpers to inspect value category of a forwarded expression ---- + +template +static constexpr bool is_lvalue(T&) +{ + return true; +} + +template +static constexpr bool is_lvalue(T&&) +{ + return false; +} + +struct movable +{ + int value; +}; + +// ---- forward lvalue ref (first overload: remove_reference_t& -> T&&) ---- + +TEST_CASE(forward_lvalue_as_lvalue) +{ + int x = 42; + // T = int&, so T&& collapses to int& (lvalue) + EXPECT(is_lvalue(rocm::forward(x))); +} + +TEST_CASE(forward_lvalue_as_rvalue) +{ + int x = 42; + // T = int, so T&& is int&& (rvalue) + EXPECT(not is_lvalue(rocm::forward(x))); +} + +TEST_CASE(forward_lvalue_preserves_value) +{ + int x = 7; + EXPECT(rocm::forward(x) == 7); + EXPECT(rocm::forward(x) == 7); +} + +// ---- forward rvalue ref (second overload: remove_reference_t&& -> T&&) ---- + +TEST_CASE(forward_rvalue_as_rvalue) +{ + // T = int, forwarding a prvalue through the rvalue overload + EXPECT(not is_lvalue(rocm::forward(42))); +} + +TEST_CASE(forward_rvalue_preserves_value) { EXPECT(rocm::forward(99) == 99); } + +// ---- return type checks ---- + +TEST_CASE(forward_return_type_lvalue_ref) +{ + // forward(...) should return int& + int x = 1; + EXPECT(rocm::is_lvalue_reference(x))>{}); + EXPECT(not rocm::is_rvalue_reference(x))>{}); +} + +TEST_CASE(forward_return_type_rvalue_ref) +{ + // forward(...) should return int&& + int x = 1; + EXPECT(rocm::is_rvalue_reference(x))>{}); + EXPECT(not rocm::is_lvalue_reference(x))>{}); +} + +TEST_CASE(forward_return_type_from_rvalue) +{ + // forward(rvalue) should return int&& + EXPECT(rocm::is_rvalue_reference(42))>{}); +} + +// ---- const qualifiers ---- + +TEST_CASE(forward_const_lvalue) +{ + const int x = 10; + EXPECT(rocm::forward(x) == 10); + EXPECT(rocm::is_lvalue_reference(x))>{}); +} + +TEST_CASE(forward_const_rvalue) +{ + const int x = 10; + EXPECT(rocm::is_rvalue_reference(x))>{}); +} + +// ---- user-defined type ---- + +TEST_CASE(forward_udt_lvalue) +{ + movable m{5}; + EXPECT(is_lvalue(rocm::forward(m))); + EXPECT(rocm::forward(m).value == 5); +} + +TEST_CASE(forward_udt_rvalue) +{ + movable m{5}; + EXPECT(not is_lvalue(rocm::forward(m))); + EXPECT(rocm::forward(m).value == 5); +} + +// ---- perfect forwarding in a generic context ---- + +template +static constexpr int perfect_forward(T&& x) +{ + return rocm::forward(x); +} + +TEST_CASE(perfect_forwarding_lvalue) +{ + int x = 3; + EXPECT(perfect_forward(x) == 3); +} + +TEST_CASE(perfect_forwarding_rvalue) { EXPECT(perfect_forward(8) == 8); } + +// ---- noexcept ---- + +TEST_CASE(forward_is_noexcept) +{ + int x = 0; + EXPECT(noexcept(rocm::forward(x))); + EXPECT(noexcept(rocm::forward(x))); + EXPECT(noexcept(rocm::forward(0))); +} diff --git a/test/gpu/kernels/rocm/utility/integer_sequence.cpp b/test/gpu/kernels/rocm/utility/integer_sequence.cpp new file mode 100644 index 00000000000..2078dcae81a --- /dev/null +++ b/test/gpu/kernels/rocm/utility/integer_sequence.cpp @@ -0,0 +1,163 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2025-2026 Advanced Micro Devices, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#include +#include +#include + +// ---- integer_sequence: value_type ---- + +TEST_CASE(integer_sequence_value_type_int) +{ + EXPECT(rocm::is_same::value_type, int>{}); +} + +TEST_CASE(integer_sequence_value_type_long) +{ + EXPECT(rocm::is_same::value_type, long>{}); +} + +TEST_CASE(integer_sequence_value_type_char) +{ + EXPECT(rocm::is_same::value_type, char>{}); +} + +TEST_CASE(integer_sequence_value_type_size_t) +{ + EXPECT(rocm::is_same::value_type, rocm::size_t>{}); +} + +// ---- integer_sequence: size ---- + +TEST_CASE(integer_sequence_size_0) { static_assert(rocm::integer_sequence::size() == 0); } + +TEST_CASE(integer_sequence_size_1) { static_assert(rocm::integer_sequence::size() == 1); } + +TEST_CASE(integer_sequence_size_3) +{ + static_assert(rocm::integer_sequence::size() == 3); +} + +TEST_CASE(integer_sequence_size_5) +{ + static_assert(rocm::integer_sequence::size() == 5); +} + +// ---- index_sequence ---- + +TEST_CASE(index_sequence_is_integer_sequence) +{ + EXPECT(rocm::is_same, + rocm::integer_sequence>{}); +} + +TEST_CASE(index_sequence_empty) +{ + EXPECT(rocm::is_same, rocm::integer_sequence>{}); +} + +TEST_CASE(index_sequence_size) { static_assert(rocm::index_sequence<0, 1, 2, 3>::size() == 4); } + +TEST_CASE(index_sequence_value_type) +{ + EXPECT(rocm::is_same::value_type, rocm::size_t>{}); +} + +// ---- make_integer_sequence ---- + +TEST_CASE(make_integer_sequence_0) +{ + EXPECT(rocm::is_same, rocm::integer_sequence>{}); +} + +TEST_CASE(make_integer_sequence_1) +{ + EXPECT(rocm::is_same, rocm::integer_sequence>{}); +} + +TEST_CASE(make_integer_sequence_3) +{ + EXPECT( + rocm::is_same, rocm::integer_sequence>{}); +} + +TEST_CASE(make_integer_sequence_5) +{ + EXPECT(rocm::is_same, + rocm::integer_sequence>{}); +} + +TEST_CASE(make_integer_sequence_long) +{ + EXPECT(rocm::is_same, + rocm::integer_sequence>{}); +} + +TEST_CASE(make_integer_sequence_unsigned) +{ + EXPECT(rocm::is_same, + rocm::integer_sequence>{}); +} + +// ---- make_index_sequence ---- + +TEST_CASE(make_index_sequence_0) +{ + EXPECT(rocm::is_same, rocm::index_sequence<>>{}); +} + +TEST_CASE(make_index_sequence_1) +{ + EXPECT(rocm::is_same, rocm::index_sequence<0>>{}); +} + +TEST_CASE(make_index_sequence_4) +{ + EXPECT(rocm::is_same, rocm::index_sequence<0, 1, 2, 3>>{}); +} + +TEST_CASE(make_index_sequence_size) { static_assert(rocm::make_index_sequence<6>::size() == 6); } + +// ---- index_sequence_for ---- + +TEST_CASE(index_sequence_for_empty) +{ + EXPECT(rocm::is_same, rocm::index_sequence<>>{}); +} + +TEST_CASE(index_sequence_for_one) +{ + EXPECT(rocm::is_same, rocm::index_sequence<0>>{}); +} + +TEST_CASE(index_sequence_for_three) +{ + EXPECT(rocm::is_same, + rocm::index_sequence<0, 1, 2>>{}); +} + +TEST_CASE(index_sequence_for_size) +{ + static_assert(rocm::index_sequence_for::size() == 4); +} diff --git a/test/gpu/kernels/rocm/utility/move.cpp b/test/gpu/kernels/rocm/utility/move.cpp new file mode 100644 index 00000000000..495057b2c24 --- /dev/null +++ b/test/gpu/kernels/rocm/utility/move.cpp @@ -0,0 +1,159 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2025-2026 Advanced Micro Devices, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#include +#include +#include + +// ---- helpers to inspect value category ---- + +template +static constexpr bool is_lvalue(T&) +{ + return true; +} + +template +static constexpr bool is_lvalue(T&&) +{ + return false; +} + +struct movable +{ + int value; +}; + +// ---- basic move converts lvalue to rvalue ---- + +TEST_CASE(move_lvalue) +{ + int x = 42; + EXPECT(is_lvalue(x)); + EXPECT(not is_lvalue(rocm::move(x))); +} + +TEST_CASE(move_preserves_value) +{ + int x = 7; + EXPECT(rocm::move(x) == 7); +} + +// ---- return type is rvalue reference ---- + +TEST_CASE(move_return_type_from_lvalue) +{ + int x = 1; + EXPECT(rocm::is_rvalue_reference{}); + EXPECT(not rocm::is_lvalue_reference{}); +} + +TEST_CASE(move_return_type_from_rvalue) +{ + EXPECT(rocm::is_rvalue_reference{}); +} + +TEST_CASE(move_return_type_from_lvalue_ref) +{ + int x = 1; + // A non-const lvalue reference is the subject under test here. + // cppcheck-suppress constVariableReference + int& rx = x; + EXPECT(rocm::is_rvalue_reference{}); +} + +// ---- exact type: move(T) yields remove_reference_t&& ---- + +TEST_CASE(move_exact_type_int) +{ + int x = 0; + EXPECT(rocm::is_same{}); +} + +TEST_CASE(move_exact_type_int_ref) +{ + int x = 0; + // Must be a non-const lvalue reference so move(rx) yields int&& (a const one would yield + // const int&& and fail the assertion below). + // cppcheck-suppress constVariableReference + int& rx = x; + EXPECT(rocm::is_same{}); +} + +TEST_CASE(move_exact_type_int_rvalue) { EXPECT(rocm::is_same{}); } + +// ---- const lvalue: move yields const T&& ---- + +TEST_CASE(move_const_lvalue) +{ + const int x = 10; + EXPECT(not is_lvalue(rocm::move(x))); + EXPECT(rocm::is_rvalue_reference{}); + EXPECT(rocm::is_same{}); +} + +// ---- user-defined type ---- + +TEST_CASE(move_udt) +{ + movable m{5}; + EXPECT(not is_lvalue(rocm::move(m))); + EXPECT(rocm::move(m).value == 5); + EXPECT(rocm::is_same{}); +} + +TEST_CASE(move_const_udt) +{ + const movable m{9}; + EXPECT(not is_lvalue(rocm::move(m))); + EXPECT(rocm::move(m).value == 9); + EXPECT(rocm::is_same{}); +} + +// ---- noexcept ---- + +TEST_CASE(move_is_noexcept) +{ + int x = 0; + EXPECT(noexcept(rocm::move(x))); + EXPECT(noexcept(rocm::move(0))); + const int cx = 0; + EXPECT(noexcept(rocm::move(cx))); +} + +// ---- move in expression context ---- + +TEST_CASE(move_in_addition) +{ + int a = 3; + int b = 4; + EXPECT(rocm::move(a) + rocm::move(b) == 7); +} + +TEST_CASE(move_chained) +{ + int x = 42; + EXPECT(rocm::move(rocm::move(x)) == 42); + EXPECT(rocm::is_rvalue_reference{}); +} diff --git a/test/gpu/kernels/rocm/utility/swap.cpp b/test/gpu/kernels/rocm/utility/swap.cpp new file mode 100644 index 00000000000..0923ad921df --- /dev/null +++ b/test/gpu/kernels/rocm/utility/swap.cpp @@ -0,0 +1,133 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2025-2026 Advanced Micro Devices, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#include +#include +#include + +// ---- basic swap ---- + +TEST_CASE(swap_int) +{ + int a = 1; + int b = 2; + rocm::swap(a, b); + EXPECT(a == 2); + EXPECT(b == 1); +} + +TEST_CASE(swap_same_value) +{ + int a = 42; + int b = 42; + rocm::swap(a, b); + EXPECT(a == 42); + EXPECT(b == 42); +} + +TEST_CASE(swap_negative) +{ + int a = -10; + int b = 20; + rocm::swap(a, b); + EXPECT(a == 20); + EXPECT(b == -10); +} + +TEST_CASE(swap_zero) +{ + int a = 0; + int b = 99; + rocm::swap(a, b); + EXPECT(a == 99); + EXPECT(b == 0); +} + +// ---- different types ---- + +TEST_CASE(swap_long) +{ + long a = 100000L; + long b = 200000L; + rocm::swap(a, b); + EXPECT(a == 200000L); + EXPECT(b == 100000L); +} + +TEST_CASE(swap_char) +{ + char a = 'x'; + char b = 'y'; + rocm::swap(a, b); + EXPECT(a == 'y'); + EXPECT(b == 'x'); +} + +TEST_CASE(swap_bool) +{ + bool a = true; + bool b = false; + rocm::swap(a, b); + EXPECT(not a); + EXPECT(b); +} + +// ---- pointer swap ---- + +TEST_CASE(swap_pointer) +{ + int x = 10; + int y = 20; + int* a = &x; + int* b = &y; + rocm::swap(a, b); + EXPECT(*a == 20); + EXPECT(*b == 10); +} + +// ---- constexpr swap ---- + +TEST_CASE(constexpr_swap) +{ + // swap is constexpr, verify via a constexpr lambda + static_assert([] { + int a = 5; + int b = 10; + rocm::swap(a, b); + return a == 10 and b == 5; + }()); +} + +// ---- swap preserves other elements ---- + +TEST_CASE(swap_array_elements) +{ + int arr[] = {1, 2, 3, 4, 5}; + rocm::swap(arr[0], arr[4]); + EXPECT(arr[0] == 5); + EXPECT(arr[4] == 1); + EXPECT(arr[1] == 2); + EXPECT(arr[2] == 3); + EXPECT(arr[3] == 4); +}