Repository navigation
Conversation
Add an offset field to the mdspan struct layout to support CCCL's upcoming cuda::layout_stride_relaxed, which handles negative strides correctly. The new struct layout is: [ptr | extents[N] | strides[N] | offset] For arrays with non-negative strides (or allow_unsafe=True), ptr is the logical data pointer and offset is 0, maintaining backward compatibility with layout_stride/layout_left/layout_right. For arrays with negative strides and allow_unsafe=False (default), ptr is the base of the allocation and offset is computed so that the layout mapping always returns a non-negative index. This makes negative strides safe by default when used with layout_stride_relaxed on the device side. Negative strides no longer require allow_unsafe=True. Only zero strides and zero-size dimensions still require it. See: cupy#9772 Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
The NumericTraits specializations for complex<float> and complex<double> marked them as primitive (is_primitive=true), which caused UB in CUB's decoupled lookback scan due to torn reads/writes when sizeof(T) >= 8. The CUB scan path for complex128 was already disabled at the Python level (cub.pyx:514) since 2020 as a workaround for this very issue. CUB device reductions (sum, min, max, argmin, argmax) and scans continue to work correctly for complex types without these traits, as CuPy provides custom operator specializations and cuda::std::numeric_limits/is_floating_point_v specializations. This also unblocks upgrading the CCCL submodule to versions containing layout_stride_relaxed, where the static_assert in ScanTileState (introduced by NVIDIA/cccl#7575) would fail for is_primitive types with sizeof >= 16. Closes: NVIDIA/cccl#8207 Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Update the CCCL submodule to dee407140b on main, which includes cuda::layout_stride_relaxed (NVIDIA/cccl#7175). This layout policy supports negative and zero strides with an explicit offset, enabling correct mdspan interop for reversed/strided array views. NOTE: This commit points to a CCCL main commit, not a stable release. Before merging this PR, the submodule should be updated to the first stable CCCL release that includes layout_stride_relaxed. Bumping CCCL is disruptive (invalidates CI cache), so we want to do it only once. Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
The offset field must be packed as ptrdiff_t (8 bytes), not IndexType, to match the C++ layout_stride_relaxed::mapping's default offset_type. This matters for IndexType=int32 where sizeof(int)=4 but the C++ struct expects an 8-byte offset field. Struct layout (2D example, IndexType=int32): [void* ptr (8B)] [int ext0, ext1 (8B)] [int str0, str1 (8B)] [ptrdiff_t offset (8B)] Total: 32 bytes = sizeof(void*) + 4*sizeof(int) + sizeof(ptrdiff_t) Struct layout (2D example, IndexType=int64): [void* ptr (8B)] [int64 ext0, ext1 (16B)] [int64 str0, str1 (16B)] [ptrdiff_t offset (8B)] Total: 48 bytes = sizeof(void*) + 4*sizeof(int64) + sizeof(ptrdiff_t) Also fixes: - _has_layout_stride_relaxed() path to use the installed CCCL symlinks - Validation test to use layout_stride_relaxed with correct sizeof - Add skip_no_relaxed_layout to TestMdspanValidation Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
- cimport ptrdiff_t from libc.stddef and use it instead of long long for the offset field in _carray.pyx - Restore original negative-stride tests with layout_stride + allow_unsafe=True (legacy path) - Add separate _relaxed test variants with layout_stride_relaxed (safe path, skip_no_relaxed_layout) - Split TestMdspanValidation into layout_stride (always runs) and TestMdspanValidationRelaxed (skip_no_relaxed_layout) - skip_no_relaxed_layout only applied to tests that exclusively target layout_stride_relaxed Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
- Add layout_stride_relaxed to the layout fixture via pytest.param with skip_no_relaxed_layout mark, so all existing tests automatically cover the relaxed layout - Merge negative-stride tests: use allow_unsafe conditionally based on layout (layout_stride=True, layout_stride_relaxed=False) - Add both-axes-reversed and sliced-negative-stride tests to TestMdspan2D (using the fixture) - Remove redundant TestMdspanStrideRelaxed class and _make_relaxed_kernel_module helper - Update skip conditions to allow both strided layout variants Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Member
Author
|
This PR is blocked until there is a public CCCL release that includes |
Draft
2 tasks
stiepan
reviewed
Jul 19, 2026
| # returns a non-negative index. | ||
| stored_ptr = mem_ptr | ||
| mem_offset = ( | ||
| (<intptr_t>data_ptr - <intptr_t>mem_ptr) // itemsize |
There was a problem hiding this comment.
Can we trust that mem_ptr is a base ptr? As an example, packages don't bother to distinguish between data ptr and base ptr when exporting memory with dlpack, so if the array converted here comes from elsewhere - this won't give us the offset. The elsewhere can by cupy itself:
>>> x = cp.arange(3 * 5, dtype=cp.int8)[::-1]
>>> x.data.ptr - x.data.mem.ptr
14
>>> y = cp.from_dlpack(x.__dlpack__())
>>> y.data.ptr - y.data.mem.ptr # both point at the last element of the array
0
Idea: ignore data.mem.ptr. Instead, compute min_offset=sum((e - 1) * s for e, s in zip(shape, strides) if s < 0 and e > 0) (note it is zero or negative), then take offset=-min_offset and mem_ptr = data.ptr + min_offset.
This branch has not been deployed
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.
Summary
Add support for CCCL's
cuda::layout_stride_relaxedto CuPy's mdspan, enabling correct handling of negative strides (reversed array views) and zero strides (broadcasting).Struct layout
The packed mdspan struct now includes an offset field:
The offset is always
ptrdiff_t(8 bytes) to matchlayout_stride_relaxed::mapping's defaultoffset_type. This is important for theIndexType=int32case where the extents and strides are 4 bytes each but the offset remains 8 bytes:ptrextents[N]strides[N]offsetxref: https://github.com/NVIDIA/cccl/blob/dee407140bde57111dd1fa9311434cb26429f035/libcudacxx/include/cuda/__fwd/mdspan.h#L82-L85
Pointer and offset semantics
allow_unsafe=True):ptr= logical data pointer,offset= 0. Backward compatible withlayout_stride,layout_left,layout_right(they ignore the trailing offset).allow_unsafe=False(default):ptr= base of allocation (arr.data.mem.ptr),offset= element distance from base to logical origin. The kernel must usecuda::layout_stride_relaxed.allow_unsafe=Truewith negative strides: legacy convention (ptr=data.ptr,offset=0) for backward compatibility withlayout_stridekernels.Negative strides no longer require
allow_unsafe=True. Only zero strides and zero-size dimensions still do.Other changes
NumericTraitsspecializations for complex types — they declaredcomplex<float/double>as primitive (is_primitive=true), causing UB in CUB's decoupled lookback scan (torn reads/writes). CUB reductions still work correctly without these traits. (Fixes [BUG] ScanTileState static_assert fails for types with is_primitive=true and sizeof >= 16 NVIDIA/cccl#8207)dee407140b(includeslayout_stride_relaxed)TestMdspanStrideRelaxedtest class with negative-stride kernel testslayout_stride_relaxedwith correctsizeofcheckMerge blocker
The CCCL submodule currently points to a
maincommit (dee407140b), not a stable release. Before merging, it should be updated to the first stable CCCL release that includeslayout_stride_relaxed. Bumping CCCL is disruptive (invalidates CI cache) so we want to do it only once.Test plan
NumericTraitsremoval (80/80)TestMdspanStrideRelaxedtests (1D/2D negative strides, both-axes reversed, sliced+reversed)Closes #9772
-- Leo's bot