Repository navigation
Conversation
HIP_ARCH was never used: enable_language(HIP) sets CMAKE_HIP_ARCHITECTURES to the GPU of the build machine before archs.cmake reads it, and hip::device compiled the C++ sources for GPU_TARGETS, also detected. HIP_ARCH now seeds CMAKE_HIP_ARCHITECTURES (an explicit value still wins), GPU_TARGETS follows it, and the default is gfx1200;gfx1201 (Navi 44 and Navi 48 can't load each other's code objects). attention_wave.h adds ATTN_WAVE_SIZE, attnShflXor and attnRequireWave32 for porting the attention DPPs to HIP. ROCm's clang no longer exposes the wave size at compile time, so a wave64 build traps at run time instead of failing the build, unless the compiler still defines __AMDGCN_WAVEFRONT_SIZE__. Nothing uses them yet; utest_attention_wave tests them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014d2rht2WMSopuodhtXYZzx
utest_flash_attention gets testFp8KV (fp8 e4m3 per-token K/V through makeFp8KVRead, oracle on the dequantized values, like testInt8KV). New utest_flash_decode covers executeFlashDecode for every loadRow path (fp32, raw bf16, int8 and fp8 caches, auto and forced splits with empty ones, two calls on one workspace) and new utest_flash_attention_mma covers executeFlashAttentionMma with raw bf16 Q/K/V, including the split-KV forward. The oracle and the Ptr1D buffer helpers move to attention_test_common.h. Writing them found three bugs in flash_decode.h, fixed here: - readElem called attnToF32 without low_precision::, so executeFlashDecode didn't compile with any generic prologue (fp32 reads, fused chains); - the packed int8/fp8 loads only handle 2 or 4 bytes per lane: HEAD_DIM 32 made a misaligned 4-byte load per lane, 256 shifted a 32-bit value by 32+; - the bf16 pair loads need an even count per lane: HEAD_DIM 32 loaded misaligned pairs and wrote past out[]. Those widths now fall back to the per-element read; 64 and 128 are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014d2rht2WMSopuodhtXYZzx
softmax.h, flash_attention.h and flash_decode.h now build their DPPs for HIP too (flash_attention_mma.h stays CUDA-only). The entry points take Stream_<defaultParArch>& (the same type as before under nvcc) and launch on getHIPStream() under HIP. Wave-size 32s and shuffles go through attention_wave.h; tile sizes are unchanged. FP8 is OCP e4m3 on both backends: attn_fp8_e4m3 is __hip_fp8_e4m3 on HIP (not the FNUZ type of gfx942) and __nv_fp8_e4m3 on CUDA, decoded by one attnFp8ToF32 used by Fp8TokenDequantRead and flash decode. attnFp8IsOcpE4M3() checks the format on known bytes. bf16 is attn_bf16. Bf16AttentionRead and the isRawBf16Read/isFp8KVRead/isInt8KVRead traits move from flash_attention_mma.h to flash_attention.h, so decode doesn't need the CUDA-only header. low_precision::attnToF32/attnFromF32 become host and device: the host KV packing helpers call them, which clang rejects for a __device__ function. The attention tests use the Ptr helpers instead of raw cudaMalloc and the new __ONLY_GPU__ marker (cmake/tests/discover_tests.cmake: no _cpp target, _cu and _hip ones), so they also run as _hip. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014d2rht2WMSopuodhtXYZzx
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
The MMA test can break older CUDA architecture builds, and numerical and workspace-reuse checks can falsely pass.
3 open issues
What changed in this PR
Ports scalar attention kernels to HIP/RDNA4 while preserving CUDA support, including the stacked architecture and test changes from #394 and #395.
Changes:
- Adds HIP attention launches, wave32 helpers, and shared low-precision types.
- Expands attention tests and replaces CUDA-specific buffer handling.
- Updates HIP architecture selection, GPU-only test discovery, and documentation.
| File | Description |
|---|---|
| utests/algorithm/attention/utest_softmax.h | Uses portable buffers and enables HIP testing. |
| utests/algorithm/attention/utest_flash_decode.h | Adds decode format and workspace-reuse tests. |
| utests/algorithm/attention/utest_flash_attention.h | Adds FP8 coverage and portable buffers. |
| utests/algorithm/attention/utest_flash_attention_mma.h | Adds CUDA bf16 MMA tests. |
| utests/algorithm/attention/utest_attention_wave.h | Tests wave reductions and exchanges. |
| utests/algorithm/attention/attention_test_common.h | Shares reference calculations and buffer helpers. |
| include/fused_kernel/algorithms/attention/softmax.h | Adds HIP launches and host-callable conversions. |
| include/fused_kernel/algorithms/attention/flash_decode.h | Enables HIP and fixes unsupported packed-load widths. |
| include/fused_kernel/algorithms/attention/flash_attention.h | Adds HIP support and shared FP8/bf16 types. |
| include/fused_kernel/algorithms/attention/flash_attention_mma.h | Moves shared reads and traits out. |
| include/fused_kernel/algorithms/attention/attention_wave.h | Adds wave32 helpers and enforcement. |
| cmake/tests/discover_tests.cmake | Supports GPU-only test markers. |
| cmake/libs/hip/hip.cmake | Aligns HIP package architecture targets. |
| cmake/libs/hip/hip_init.cmake | Seeds architectures before HIP initialization. |
| cmake/libs/hip/archs.cmake | Applies the selected HIP architectures. |
| AGENTS.md | Documents HIP attention and test configuration. |
Review effort: Balanced
| inline double maxAbsErr(const std::vector<T>& got, const std::vector<double>& ref) { | ||
| double maxErr = 0.0; | ||
| for (size_t i = 0; i < ref.size(); ++i) { | ||
| maxErr = std::max(maxErr, std::abs(static_cast<double>(got[i]) - ref[i])); |
Comment on lines
+50
to
+51
| executeFlashDecode<HEAD_DIM>(q, k, v, o.ptr().data, workspace.ptr().data, bh, seqK, stream, | ||
| -1.f, splitsOverride); |
…rst configure Follows 1cf881b: the comment in hip_init.cmake and AGENTS.md still said HIP_ARCH defaulted to gfx1200;gfx1201 and was re-applied on reconfigure. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014d2rht2WMSopuodhtXYZzx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.


Phase 3 of the RDNA4 port: the scalar attention DPPs and the FP8 KV cache run on HIP (RX 9060, gfx1200).
Stacked on #394 and #395: this branch contains their commits. Review those first; once they merge, this diff shrinks to the last commit (
7c78320).Changes
softmax.h,flash_attention.handflash_decode.hnow build their DPPs under__NVCC__ || __HIPCC__. HIP launches usegetHIPStream()/hipGetLastError(), the CUDA launch lines are unchanged in#else, and HIP kernels callattnRequireWave32().flash_attention_mma.hstays CUDA-only and is still harmless to include on HIP.attnShflXor, and the 32s that mean "lanes per wave" useATTN_WAVE_SIZE. Every remaining 32 is a tile size (BLOCK_N) and is untouched. The 5 shuffle sites in the MMA file are unchanged.__HIPCC__ && __has_include(<hip/hip_fp8.h>)→__hip_fp8_e4m3, not the FNUZ__hip_fp8_e4m3_fnuzof gfx942); the CUDA condition is still exactly__has_include(<cuda_fp8.h>). The type isfk::attn_fp8_e4m3, decoded by a singleattnFp8ToF32()used byFp8TokenDequantRead, flash decode and the tests.attnFp8IsOcpE4M3()checks known bytes (0x7E = 448, 0x38 = 1, 0x80 = -0). On this ROCm (10.1), device and host decoding and encoding give OCP values, and encoding saturates at 448 like CUDA'ssatfinite.Bf16AttentionRead, itsmakeAttentionReadoverload and theisRawBf16Read/isFp8KVRead/isInt8KVReadtraits moved fromflash_attention_mma.htoflash_attention.h, so decode doesn't need the CUDA-only header. They have the same names and code, with bf16 spelledattn_bf16/attn_bf162(__nv_*under nvcc).flash_decode.hstill includes the MMA header.utest_flash_attention,utest_softmax,utest_flash_decodeandutest_attention_wavenow usePtrinstead of rawcudaMalloc/cudaMemcpy[2D], and are marked with the new__ONLY_GPU__.cmake/tests/discover_tests.cmake: anONLY_GPUsubstring suppresses only the_cpptarget. No existing file contains that substring.AGENTS.mddocuments the marker and the HIP status ofattention/.utest_flash_attentionadds an fp8 format check (testFp8Format).CUDA-visible changes (same types and behavior; all compiled with nvcc 13.4)
They don't change behavior, but they aren't token-identical:
Stream_<defaultParArch>&, which isStream_<ParArch::GPU_NVIDIA>&under nvcc.low_precision::attnToF32/attnFromF32are nowFK_HOST_DEVICE_CNSTinstead ofFK_DEVICE_CNST. The host packing helpers (quantizeKVCacheHost,quantizeKVCacheFp8Host) already called them from host code. nvcc accepts that for aconstexpr __device__function, but HIP's clang doesn't.Fp8TokenDequantRead::execdecodes throughattnFp8ToF32, which sets__xand converts. The old device branch reinterpreted the byte as__nv_fp8_e4m3; the old host branch already used the new code.% ATTN_WAVE_SIZEinstead of& 31, and so on) andattnShflXor, which is__shfl_xor_sync(0xffffffffu, …)on CUDA.Verified on this machine (RX 9060, gfx1200, ROCm 10.1)
Full HIP suite with default arches (gfx1200;gfx1201): 51/51, the 47 on
mainplusutest_attention_wave_hip,utest_softmax_hip,utest_flash_attention_hipandutest_flash_decode_hip. Same unique warnings asmain.Measured max errors on HIP:
Decode covers fp32, bf16 (including d32/d256), int8 and fp8, with empty splits and repeated calls.
Mutation checks: making the shuffle reduction stop one step early fails every dense case (max error 0.05 to 0.28). Decoding fp8 at twice the value fails the format check. The KV cases can't catch that one, because the oracle decodes with the same function, which is why the format check exists.
nvcc 13.4 + g++-13, sm_86 (PyPI wheels, no GPU): full build with 0 failures and 0 warnings; the 49
_cpptests pass, and the_cpplist is the same as RDNA4 phase 2: CUDA tests for FP8 KV, flash decode and the mma kernel (CUDA-side, unverified locally) #395's.Needs CUDA CI
Running
utest_flash_attention_cu,utest_softmax_cu,utest_flash_decode_cu,utest_flash_attention_mma_cuandutest_attention_wave_cuon the A2000, after the changes above.🤖 Generated with Claude Code
https://claude.ai/code/session_014d2rht2WMSopuodhtXYZzx