335 add hip backend - #355
Conversation
albertandaluz
commented
Aug 25, 2026
- adds HIP langugag esupprot via cmake
- updates scripts to generate HIP tests and bennchmakrs based on cuda codegen
- sets separare preprocessor ocmpilation paths for HIP and CUDA
- adds a new CI bare metal linux runner for HIP/rocm compilation . (windows is excluded since building WSL2 has some bugs in pinned memory in DXROG compatibility)
- fixes several bugs in tests detected during porting
There was a problem hiding this comment.
Pull request overview
This PR introduces a HIP/ROCm backend path alongside the existing CPU/CUDA support, updating the execution model, vector utilities, memory/stream abstractions, and CMake/CI to generate and run HIP-based tests and benchmarks.
Changes:
- Add HIP language support through CMake (new HIP helpers, test/benchmark codegen, and CI workflow for ROCm builds).
- Extend core runtime abstractions to support
ParArch::GPU_AMD(stream/executor/DPP kernels and vector type handling). - Fix/adjust several tests and algorithm behaviors uncovered during HIP porting (e.g., constexpr comparisons, pixel normalization/denormalization).
Reviewed changes
Copilot reviewed 44 out of 44 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
CMakeLists.txt |
Adds ENABLE_HIP/ENABLE_CUDA toggles and HIP language initialization logic. |
cmake/hip_init.cmake |
Enables HIP language and pulls in HIP build helpers. |
cmake/libs/hip/hip.cmake |
Defines HIP target wiring (add_hip_to_target) and links HIP device runtime. |
cmake/libs/hip/archs.cmake |
Introduces HIP arch flag configuration via HIP_ARCH. |
cmake/libs/hip/debug.cmake |
Adds HIP debug/lineinfo compile options. |
cmake/libs/hip/target_generation.cmake |
Sets default HIP target properties (standard, runtime, template depth). |
cmake/tests/discover_tests.cmake |
Extends test discovery to generate HIP test targets. |
cmake/tests/add_generated_test.cmake |
Adds add_hip_to_test() and HIP language handling for generated launchers. |
cmake/tests/add_shared_test_libs.cmake |
Hooks shared test libs into HIP test targets. |
cmake/discover_tests.cmake |
Removes older duplicated generated-test logic (now centralized elsewhere). |
benchmarks/CMakeLists.txt |
Adds HIP benchmark generation and target wiring. |
benchmarks/fkBenchmarksCommon.h |
Adds ROCm event-based timing for ParArch::GPU_AMD. |
include/fused_kernel/core/execution_model/parallel_architectures.h |
Sets defaultParArch to GPU_AMD under HIP compilation. |
include/fused_kernel/core/execution_model/stream.h |
Adds Stream_<ParArch::GPU_AMD> with HIP stream lifecycle and sync. |
include/fused_kernel/core/execution_model/executor_details/executor_kernels.h |
Makes kernels compile under HIP (guards + __grid_constant__ portability). |
include/fused_kernel/core/execution_model/data_parallel_patterns.h |
Enables Transform/Divergent DPP execution paths for GPU_AMD. |
include/fused_kernel/core/execution_model/executors.h |
Adds executor implementations for HIP (TransformDPP and divergent batch) and broadens supported PA checks. |
include/fused_kernel/core/utils/utils.h |
Adds HIP runtime include and HIP error checking (gpuAssert for hipError_t). |
include/fused_kernel/core/data/vector_types.h |
Uses HIP vector type headers under __HIPCC__. |
include/fused_kernel/core/utils/vector_utils.h |
Adjusts vector construction helpers to accommodate HIP vector type semantics. |
include/fused_kernel/core/data/ptr_nd.h |
Adds HIP allocation/free and async copy support for Ptr memory management and transfers. |
include/fused_kernel/core/data/ptr_utils.h |
Generalizes GPU path to include GPU_AMD. |
include/fused_kernel/algorithms/image_processing/image.h |
Adds HIP upload/download helpers for Image. |
include/fused_kernel/algorithms/image_processing/interpolation.h |
Adapts device-side code paths for HIP arch macros and type handling. |
include/fused_kernel/algorithms/image_processing/deinterlace.h |
Adjusts pixel math/type casting and interpolation guard logic. |
include/fused_kernel/algorithms/image_processing/color_conversion.h |
Fixes normalization/denormalization math to avoid HIP vector operator narrowing. |
include/fused_kernel/algorithms/basic_ops/logical.h |
Avoids reliance on vector == operator behavior by comparing per-component. |
tests/launcher.in |
Updates copyright year range. |
tests/data/basic_test.h |
Renames log strings from “cuda_transform” to “gpu_transform”. |
tests/data/test_ptr_nd.h |
Adjusts comparison result type in test to match backend behavior. |
utests/algorithm/image_processing/utest_color_conversion.h |
Fixes expected denormalization values and makes matrix equality constexpr-friendly. |
utests/algorithm/image_processing/utest_saturate/CMakeLists.txt |
Adds HIP-generated unit test targets for saturate tests. |
utests/algorithm/image_processing/utest_saturate/utest_saturate_ftype.hip.in |
New HIP test template for saturate fundamental-type variants. |
lib/CMakeLists.txt |
Marks public include dirs as SYSTEM (to reduce warnings for consumers). |
lib/export/FKLTargets.cmake |
Adjusts exported imported-target definition (but currently introduces invalid CMake syntax). |
README.md |
Updates documentation to mention ROCm backend and supported environments. |
.github/workflows/cmake-linux-rocm-amd64.yml |
New ROCm CI workflow on self-hosted runner. |
.github/workflows/cmake-linux-cuda-amd64.yml |
Labels as CUDA workflow and forces CUDA/HIP toggles. |
.github/workflows/cmake-linux-arm64.yml |
Labels as CUDA workflow and forces CUDA/HIP toggles. |
.github/workflows/cmake-windows-cuda-amd64.yml |
Labels as CUDA workflow and forces CUDA/HIP toggles. |
.github/workflows/cmake-windows-rocm-amd64.yml.disabled |
Adds (disabled) Windows ROCm workflow file. |
.github/workflows/copilot-setup-steps.yml |
Updates CMake toolchain path. |
.github/copilot-instructions.md |
Updates documented CI toolchain path. |
include/fused_kernel/core/utils/compiler_macros.h.rej |
Removes a stray patch reject artifact from the tree. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 44 out of 44 changed files in this pull request and generated 1 comment.
Suppressed comments (4)
Previously missed (1) — in code that hasn't changed since the last review.
README.md:177
- README states ROCm is supported on Windows, but this PR explicitly excludes Windows ROCm (the workflow is committed as
.disabled). This is a discrepancy between the PR description and the documentation added here.
For ROCM builds (x86_64 only):
- Ubuntu 24.04 + ROCM 7.2
- Windows 11 Visual Studio 2022 + ROCM 7.2 amd64 systems.
include/fused_kernel/algorithms/image_processing/deinterlace.h:92
execBlend()readsthread.y + 1whenthread.y > 0without checking that the current thread is not on the last row. Forthread.y == height - 1this will read past the image bounds and can cause invalid memory access / wrong pixels.
if (thread.y > 0) {
const auto above = cxp::cast<OutputType>::f(
ReadOperation::exec(Point{thread.x, thread.y - 1, thread.z}, backIOp));
const auto below = cxp::cast<OutputType>::f(
ReadOperation::exec(Point{thread.x, thread.y + 1, thread.z}, backIOp));
return (current + above + below + 1.f) * 0.25f;
CMakeLists.txt:47
- HIP setup uses
HIP_PATHto extendCMAKE_MODULE_PATHbeforeHIP_PATHis initialized. If callers don’t pass-DHIP_PATH=...or the env var isn’t set, this expands to/cmakeand can lead to confusing configuration behavior.
set(CMAKE_MODULE_PATH "${HIP_PATH}/cmake" ${CMAKE_MODULE_PATH})
set(CMAKE_CXX_SCAN_FOR_MODULES OFF) #clang with HIP does not come with clang-scan-deps
include(cmake/hip_init.cmake)
lib/export/FKLTargets.cmake:53
add_library()does not accept theSYSTEMkeyword. This line will fail CMake configuration when consumers use the installed/exported package config.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 44 out of 44 changed files in this pull request and generated no new comments.
Suppressed comments (6)
Previously missed (4) — in code that hasn't changed since the last review.
cmake/libs/hip/hip.cmake:8
- On Linux, HIP discovery hardcodes
/opt/rocm/core, but CI/workflows setHIP_PATHto a versioned prefix (e.g./opt/rocm/core-7.14). Hardcoding this path makesfind_package(HIP CONFIG REQUIRED)brittle across runner layouts.
if (WIN32)
list(APPEND CMAKE_PREFIX_PATH $ENV{HIP_PATH})
else()
#linux
list(APPEND CMAKE_PREFIX_PATH /opt/rocm/core)
include/fused_kernel/core/execution_model/stream.h:151
Ref::getRefCount()returns the current reference count including*this(seeref_class.h). In the HIP stream destructor, checkinggetRefCount() == 0will never be true, so ownedhipStream_tinstances won't be destroyed.
benchmarks/fkBenchmarksCommon.h:135- HIP-specific code here is guarded by
__HIP__, but the rest of the codebase (andgpuErrchk/HIP runtime includes) are keyed off__HIPCC__. Using__HIP__alone can miss HIP builds where only__HIPCC__is defined.
#if defined(__HIP__)
README.md:177
- README lists ROCm 7.2 and Windows ROCm testing, but the ROCm CI workflow introduced in this PR uses a 7.14 install prefix and the Windows ROCm workflow is committed as disabled. This section should reflect the versions/platforms that are actually covered by CI in this repo.
For ROCM builds (x86_64 only):
- Ubuntu 24.04 + ROCM 7.2
- Windows 11 Visual Studio 2022 + ROCM 7.2 amd64 systems.
lib/export/FKLTargets.cmake:53
add_library()does not accept aSYSTEMkeyword in this position (CMake 3.28+). This line will make the exported targets file fail to load for consumers.
CMakeLists.txt:49HIP_PATHis used to extendCMAKE_MODULE_PATHbefore it is initialized, andcmake/hip_init.cmakeis included beforeHIP_PATHis set. This can result in HIP package discovery using an empty/incorrect path.
set(CMAKE_MODULE_PATH "${HIP_PATH}/cmake" ${CMAKE_MODULE_PATH})
set(CMAKE_CXX_SCAN_FOR_MODULES OFF) #clang with HIP does not come with clang-scan-deps
include(cmake/hip_init.cmake)
if(NOT DEFINED HIP_PATH)
if(NOT DEFINED ENV{HIP_PATH})
Addressed in commit 17475f7.
|
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 43 out of 43 changed files in this pull request and generated 1 comment.
Suppressed comments (4)
Previously missed (3) — in code that hasn't changed since the last review.
include/fused_kernel/algorithms/image_processing/interpolation.h:98
- The
* 1.finside the cast when reading the 2x2 source pixels is redundant (the cast already selects OutputType) and adds noise. It also makes it harder to reason about which operator overload is actually being used across CUDA/HIP.
const auto src_reg0x0 = cxp::cast<OutputType>::f(BackIOp::Operation::exec(readPoints._0x0, backIOp)*1.f);
const auto src_reg1x0 = cxp::cast<OutputType>::f(BackIOp::Operation::exec(readPoints._1x0, backIOp)*1.f);
const auto src_reg0x1 = cxp::cast<OutputType>::f(BackIOp::Operation::exec(readPoints._0x1, backIOp)*1.f);
const auto src_reg1x1 = cxp::cast<OutputType>::f(BackIOp::Operation::exec(readPoints._1x1, backIOp)*1.f);
include/fused_kernel/core/utils/utils.h:129
message.append(std::to_string(line).c_str())takes a pointer to a temporary string buffer. While it happens to work, it’s unnecessarily brittle and can be simplified by appending the std::string directly.
cmake/tests/add_generated_test.cmake:70- add_generated_test_stub() uses
${TARGET_NAME}and${EXTENSION}without taking them as parameters, relying on CMake’s dynamic scoping from the caller. This makes the function easy to misuse and harder to understand (its signature doesn’t reflect its required inputs).
function (add_generated_test_stub TARGET_NAME_EXT TEST_SOURCE DIR)
set(TEST_GENERATED_SOURCE "${CMAKE_CURRENT_BINARY_DIR}/${TARGET_NAME}_${EXTENSION}/launcher.${EXTENSION}") #use the same name as the target )
configure_file(${CMAKE_SOURCE_DIR}/tests/launcher.in ${TEST_GENERATED_SOURCE} @ONLY) #replace variables in the test source file
include/fused_kernel/algorithms/image_processing/deinterlace.h:113
- In execInterLinearGetPixel(), the interpolate/else returns are inconsistently formatted and include redundant
* 1.fmultiplications and an integer+ 1literal. This hurts readability and is inconsistent with execBlend() above, without changing behavior.
return (above*1.f + below*1.f + 1) * 0.5f;
} else {
return cxp::cast<OutputType>::f(
ReadOperation::exec(thread, backIOp) * 1.f);
}
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 43 out of 43 changed files in this pull request and generated no new comments.
Suppressed comments (2)
Previously missed (1) — in code that hasn't changed since the last review.
lib/CMakeLists.txt:10
target_include_directories(... SYSTEM INTERFACE ...)marks this project's own public headers as system headers for all consumers (and often for in-repo builds too), which suppresses diagnostics coming from FKL headers. This makes it easier to miss warnings/regressions (especially important while bringing up a new HIP backend). Consider removingSYSTEMfor the project's own include directory.
include/fused_kernel/algorithms/image_processing/deinterlace.h:113
- In the interlinear path, the expression mixes
OutputTypevectors with an untyped integer literal (+ 1). On HIP, mixed scalar/vector operators can resolve to HIP-native vector operators and cause narrowing / integer arithmetic (similar to the issues addressed elsewhere in this PR). Use a float literal and drop the redundant* 1.fto keep the math in the intended type.
return (above*1.f + below*1.f + 1) * 0.5f;
} else {
return cxp::cast<OutputType>::f(
ReadOperation::exec(thread, backIOp) * 1.f);
}
8e630a0 to
cbf7bae
Compare
Co-authored-by: albertandaluz <176801700+albertandaluz@users.noreply.github.com>
Co-authored-by: albertandaluz <176801700+albertandaluz@users.noreply.github.com>
Co-authored-by: albertandaluz <176801700+albertandaluz@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
ff877a5 to
2ef116e
Compare
| message.append(" Line:"); | ||
| message.append(std::to_string(line).c_str()); | ||
| message.append("\n"); |
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 44 out of 45 changed files in this pull request and generated 6 comments.
Suppressed comments (3)
include/fused_kernel/core/utils/utils.h:1
- The HIP
gpuAssertbuilds the message usingmessage.append(std::to_string(line).c_str())and throwsstd::runtime_error(message.c_str()). It’s simpler and safer to append thestd::stringdirectly (avoids relying on a temporary’sc_str()lifetime) and throwstd::runtime_error(message)to avoid an unnecessary C-string conversion.
include/fused_kernel/core/utils/vector_utils.h:1 - The static_assert message mentions "non cuda vector type", but this code path is now relevant for HIP as well. Consider updating the wording to a backend-neutral message (e.g., "non-GPU vector type" or "non-supported vector type") so failures are less confusing in HIP builds.
utests/algorithm/image_processing/utest_saturate/utest_saturate_ftype.hip.in:1 - This new template file appears to start with a UTF-8 BOM (the invisible character before
/*). Some toolchains and generators can mishandle BOMs (especially when concatenating/templating sources). Consider removing the BOM and ensuring the file is plain UTF-8 without BOM for maximum portability.
| const auto current = cxp::cast<OutputType>::f(ReadOperation::exec(thread, backIOp)); | ||
|
|
||
| if (thread.y > 0) { | ||
| const auto above = ReadOperation::exec(Point{thread.x, thread.y - 1, thread.z}, backIOp); | ||
| return (current + above + 1) * 0.5f; | ||
| const auto height = ReadOperation::num_elems_y(Point{0,0,0}, backIOp); | ||
| if (thread.y > 0 && thread.y + 1 < height) { | ||
| const auto above = cxp::cast<OutputType>::f( | ||
| ReadOperation::exec(Point{thread.x, thread.y - 1, thread.z}, backIOp)); | ||
|
|
||
| const auto below = cxp::cast<OutputType>::f( | ||
| ReadOperation::exec(Point{thread.x, thread.y + 1, thread.z}, backIOp)); | ||
|
|
||
| return (current + above + below + 1.f) * 0.25f; |
| const auto above = cxp::cast<OutputType>::f( | ||
| ReadOperation::exec(Point{thread.x, thread.y - 1, thread.z}, backIOp)); | ||
|
|
||
| const auto below = cxp::cast<OutputType>::f( | ||
| ReadOperation::exec(Point{thread.x, thread.y + 1, thread.z}, backIOp)); | ||
|
|
||
| return (above*1.f + below*1.f + 1) * 0.5f; | ||
| } else { | ||
| return ReadOperation::exec(thread, backIOp) * 1.f; | ||
| return cxp::cast<OutputType>::f( | ||
| ReadOperation::exec(thread, backIOp) * 1.f); |
| }; | ||
|
|
||
| #if defined(__CUDACC__) || defined(__HIP__) | ||
| #if defined(__CUDACC__) |
| #endif // defined(__CUDACC__) | ||
|
|
||
| #if defined(__HIP__) |
| if (${ENABLE_DEBUG}) | ||
| add_hip_debug_support_to_target(${TARGET_NAME}) | ||
| endif() | ||
| if (${ENABLE_HIP_LINE_INFO}) |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 44 out of 45 changed files in this pull request and generated no new comments.
Suppressed comments (4)
Previously missed (1) — in code that hasn't changed since the last review.
include/fused_kernel/core/data/ptr_nd.h:194
- This error message (and several similar ones in this file) still says "non-CUDA compilation", but these code paths are now also enabled under HIP. Updating the wording to mention both CUDA and HIP (or just "non-GPU compilation") will make failures clearer when ENABLE_HIP is used.
#else
throw std::runtime_error("Device allocation not supported in non-CUDA compilation.");
#endif
include/fused_kernel/algorithms/image_processing/deinterlace.h:113
- In execInterLinearGetPixel()'s non-interpolate path, the value is multiplied by 1.f before being cast to OutputType. If ReadOperation::exec returns an integer vector type, this can route through the backend's native vector operator and perform integer arithmetic/truncation before the cast (similar to the HIP issue described in color_conversion.h). Also, the current formatting makes the return statement hard to read.
return (above*1.f + below*1.f + 1) * 0.5f;
} else {
return cxp::cast<OutputType>::f(
ReadOperation::exec(thread, backIOp) * 1.f);
}
benchmarks/fkBenchmarksCommon.h:136
- HIP-only benchmark specializations are guarded with HIP, but the rest of the codebase consistently uses HIPCC to detect HIP compilation. If HIP is not defined by the compiler/toolchain, this block will be skipped and the GPU_AMD TimeMarker specialization won't be available.
#if defined(__HIP__)
template <>
benchmarks/fkBenchmarksCommon.h:312
- Same issue as above: the GPU_AMD TimeMarkerTwo specialization is guarded with HIP. Using HIPCC here matches the rest of the repository's HIP compilation checks and avoids the specialization being skipped depending on toolchain macros.
#if defined(__HIP__)
template <>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 44 out of 45 changed files in this pull request and generated 4 comments.
Suppressed comments (2)
include/fused_kernel/core/utils/vector_utils.h:1
- Switching
make_fromstd::is_aggregate_v<T>tovector_type<T>changes behavior for non-vector aggregates: types that previously could be aggregate-initialized with multiple arguments will now hard-fail thestatic_assert. Ifmake_is intended to remain a generic aggregate helper, consider restoring an aggregate branch (or splitting intomake_vector_vs a generic aggregate factory). Also, the assertion message should be updated to not mention only CUDA now that HIP is supported.
include/fused_kernel/core/execution_model/executors.h:1 - This
#endifcomment is now inaccurate: the corresponding#ifguard was widened todefined(__NVCC__) || defined(__HIPCC__). Please update the comment to match the actual condition to reduce confusion during future maintenance.
| const auto above = cxp::cast<OutputType>::f( | ||
| ReadOperation::exec(Point{thread.x, thread.y - 1, thread.z}, backIOp)); | ||
|
|
||
| const auto below = cxp::cast<OutputType>::f( | ||
| ReadOperation::exec(Point{thread.x, thread.y + 1, thread.z}, backIOp)); | ||
|
|
||
| return (above*1.f + below*1.f + 1) * 0.5f; | ||
| } else { | ||
| return ReadOperation::exec(thread, backIOp) * 1.f; | ||
| return cxp::cast<OutputType>::f( | ||
| ReadOperation::exec(thread, backIOp) * 1.f); |
| #endif | ||
| } | ||
| #else | ||
| throw std::runtime_error("Device allocation not supported in non-CUDA compilation."); |
| set(HIP_ARCH "gfx1200" CACHE STRING "HIP architecture(s) to build") | ||
|
|
||
| function(set_target_hip_arch_flags TARGET_NAME) |
| if (${ENABLE_DEBUG}) | ||
| add_hip_debug_support_to_target(${TARGET_NAME}) | ||
| endif() | ||
| if (${ENABLE_HIP_LINE_INFO}) |