fix(cuda): map host complex types to CUDA storage ids - #1116
Conversation
|
Caution The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased. |
|
Caution The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased. |
d86c77c to
0648875
Compare
Why this fails on Windows/MSVC but succeeds on Linux/GCCI investigated the failure path and the relevant standard-library implementations. The most accurate conclusion is:
The distinction matters because the first part is a correctness fix, while the dispatch rewrite is a CUDA-compiler portability workaround. 1. The original GPU complex type-id lookup is objectively wrongCytnx's logical dtype list contains host complex types: using Type_list = std::variant<
void,
std::complex<double>,
std::complex<float>,
...>;whereas using Type_list_gpu = std::variant<
void,
cuda::std::complex<double>,
cuda::std::complex<float>,
...>;The previous definition nevertheless performed: variant_index_v<T, Type_list_gpu>for an ordinary Cytnx dtype variant_index_v<
std::complex<double>,
std::variant<void, cuda::std::complex<double>, ...>>Those are different C++ types, so the lookup must eventually reach the empty-variant base case and fire: The new std::complex<float> -> cuda::std::complex<float>
std::complex<double> -> cuda::std::complex<double>
all other types -> unchangedThe PR's A/B experiment is especially useful here:
That isolates the type mapping and the 2. Linux success does not prove the old lookup was validA class-template specialization does not necessarily instantiate the definitions/initializers of all of its static data members merely because the enclosing class is instantiated. The C++ implicit-instantiation rules explicitly distinguish instantiating member declarations from instantiating their definitions: Consequently, an invalid dependent initializer can remain latent until some compilation path actually requires it. The fact that the Linux CUDA build did not diagnose this member does not make the lookup correct; it means that the Linux NVCC/GCC/libstdc++ compilation path did not require the same instantiation at that point. I would avoid attributing this solely to 3. The second failure is not a normal MSVC diagnostic:
|
| Standard library | General two-variant dispatch structure |
|---|---|
| Microsoft STL | Cartesian-product index metadata + valueless states + stamped switch strategy |
| libstdc++ | Recursive multidimensional function-pointer table |
The Linux build succeeding therefore does not imply better language-feature support in GCC. It indicates that libstdc++ generates a different template/AST shape that does not trigger this Windows cudafe++ failure.
6. Why the dtype-indexed recursive dispatch succeeds
The replacement dispatch still instantiates the complete 11 × 11 type matrix:
dispatch_lhs<LIndex>()
-> dispatch_rhs<TL, RIndex>()
-> launch<TO, TL, TR>()Therefore it preserves:
- exhaustive compile-time type coverage;
- the existing promotion rules;
- the same CUDA-native
to_cuda_tboundary; - scalar, contiguous, and non-contiguous launch paths;
- checked erased-to-typed storage recovery via
storage_cast.
What it removes is the standard-library visitation machinery surrounding those leaf instantiations:
- no Microsoft STL Cartesian-product type list;
- no valueless dispatch states;
- no
_Variant_dispatcherwrapper for every state; - no 256-case stamped switch;
- no multi-variant return-type metaprogramming path.
The new template graph is two shallow, predictable chains of if constexpr recursion. It does not reduce the set of Cytnx type combinations, but it is substantially easier for the CUDA front end to lower.
7. Recommended characterization of this PR
I would describe the two changes separately:
- Correctness fix: map logical host
std::complex<T>dtypes to CUDA-nativecuda::std::complex<T>before looking them up inType_list_gpu. - Compiler-portability workaround: replace the two-variant
std::visitin CUDA translation units with dtype-indexed template dispatch to avoid a CUDA 13.3 Windowscudafe++access violation triggered by Microsoft STL's large visitation implementation.
A technically precise summary would be:
The old code contains a latent host-complex/CUDA-complex type-id mismatch. After correcting that mismatch, the otherwise valid two-variant visitation still triggers an NVIDIA
cudafe++compiler crash on Windows because Microsoft STL lowers this 11 × 11 visitation through a large Cartesian-product/switch template structure. libstdc++ uses a different multidimensional jump-table implementation, so Linux does not exercise the same compiler failure. The recursive dtype dispatcher preserves exhaustive typed dispatch while avoiding that problematic standard-library instantiation.
The existing PR title is understandable shorthand, but comments and release notes should ideally say "CUDA/NVCC Windows front-end crash with the MSVC host toolchain/STL" rather than implying that cl.exe or MSVC's C++ feature set is incomplete.
A reduced reproducer could later be filed with NVIDIA, but I do not think that should block this patch: a compiler access violation is sufficient justification for using the simpler, semantically equivalent dispatch structure here.
Follow-up after the unlimited template-instantiation backtraceThe newly added The trace shows this chain for both host complex types: and equivalently for This means the first diagnostic is not triggered by the two-variant More importantly, static constexpr Type_struct construct() {
return {name, enum_name, is_unsigned, is_complex, is_float, is_int, typeSize};
}The class specialization contains Under the C++ implicit-instantiation rule, instantiating a class-template specialization instantiates the declarations, but not the definitions, of its static data members. See
https://eel.is/c++draft/temp.inst Therefore, the complete trace supports a stronger and more precise diagnosis than my earlier wording:
The invalid initializer remains a real latent defect in Cytnx: variant_index_v<std::complex<double>, Type_list_gpu>cannot succeed because The A/B result then keeps the two failures cleanly separated:
So the refined attribution is:
|
0648875 to
618b09c
Compare
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #1116 +/- ##
=======================================
Coverage 73.06% 73.06%
=======================================
Files 224 224
Lines 27642 27642
Branches 71 71
=======================================
Hits 20196 20196
Misses 7425 7425
Partials 21 21
Flags with carried forward coverage won't be shown. Click here to find out more.
Continue to review full report in Codecov by Harness.
🚀 New features to boost your workflow:
|
Map host complex types to CUDA-native storage ids and replace the two-variant std::visit expansion with dtype-indexed template dispatch. This preserves promotion semantics while avoiding cudafe++ failures on Windows. Co-Authored-By: OpenAI Codex <codex@openai.com>
618b09c to
dff7aad
Compare
|
I finally found the |
Problem
Cytnx's logical dtype list uses host
std::complextypes, whileType_list_gpuuses CUDA-nativecuda::std::complextypes. Looking up a host complex type directly inType_list_gpuis therefore invalid when the GPU type-id member is instantiated.The previously observed
cudafe++crash is the Boost 1.89+constexpr intrusive_ptrfrontend bug tracked in #1124, not a reason to replace Cytnx's two-variant visitation.Fix
std::complex<double>tocuda::std::complex<double>before GPU variant lookup;std::complex<float>tocuda::std::complex<float>before GPU variant lookup;std::visitimplementation.The final PR diff changes only
include/Type.hpp. It does not add a CMake Boost-version rejection. The wheel dependency pin for Boost<1.89is already handled by #1124 onmaster.Testing
1;2;3;git diff --check: passed;master.Part of #1114. Related compiler issue and dependency pin: #1124.