fix(cuda): avoid NVCC/cudafe++ crashes on Windows when processing MSVC STL multi-variant visitation.#1116
fix(cuda): avoid NVCC/cudafe++ crashes on Windows when processing MSVC STL multi-variant visitation.#1116IvanaGyro wants to merge 1 commit into
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. |
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>
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:
|
| if (Lin->dtype() == static_cast<int>(LIndex)) { | ||
| dispatch_rhs<op_code, TLc>(out, Lin, Rin, len, shape, invmapper_L, invmapper_R); | ||
| } else if constexpr (LIndex + 1 < std::variant_size_v<Type_list>) { |
There was a problem hiding this comment.
I am not sure if compiler will optimize this to a function table. Maybe using two-fold visit is a better choice.
Base and downstream topology
This PR is a single commit directly on
master.The later Windows PRs still need the unmerged #1109 and #1110 changes. Their integration history is preserved by
codex/windows-msvc-cuda-stack, which points at the former combined #1116 tip and contains the same #1116 patch:#1109 ? #1110 ? codex/windows-msvc-cuda-stack ? #1117 ? #1118 ? #1119 ? #1113#1117 is based on that integration anchor. The master-based patch and the original stacked patch have the same stable Git patch ID (
025bfb1307f96ff9f4977e7137cde1a8f7358e97).Summary
std::complextypes to their CUDA-nativecuda::std::complexstorage type ids;std::visitexpansion with dtype-indexed template dispatch;cudafe++crashes with MSVC.This is a Windows CUDA compiler-portability fix. It is not a blocker for Linux CUDA or Windows CPU builds. It is the only split PR with mixed-dtype implementation changes and requires focused human review.
Why Linux succeeds
A successful
openblas-cudaordebug-openblas-cudabuild on Linux is expected. Linux runsnvccwith a GCC/Clang host toolchain; the failing path here is CUDA 13.3's Windows front end processing MSVC's largestd::visitinstantiation. Linux builds are important regression coverage, but they do not exercise the MSVC-specific failure.Windows A/B reproduction
The parent and fixed revisions were tested with:
cudaenvironment;USE_CUDA=ON,USE_CUTENSOR=ON,USE_CUQUANTUM=OFF,USE_MKL=ON;BUILD_PYTHON=OFF,USE_HPTT=OFF, and IPO disabled for the focused compile;CMAKE_CUDA_ARCHITECTURES=75for the A/B reproduction;CMakeFiles/cytnx.dir/src/backend/linalg_internal_gpu/cuAdd_internal.cu.obj.Results:
On fix(cuda): avoid NVCC/cudafe++ crashes on Windows when processing MSVC STL multi-variant visitation. #1116's original stacked parent (
1fc237fa), the object fails because hoststd::complex<float/double>is not present inType_list_gpu, then the CUDA front end terminates:Applying only the host-complex ? CUDA-complex mapping removes both static assertions, but the unchanged two-variant dispatcher still ends with the same
cudafe++access violation.With the complete fix(cuda): avoid NVCC/cudafe++ crashes on Windows when processing MSVC STL multi-variant visitation. #1116 change, incremental MSVC/CUDA 13 compilation succeeds for
cuAdd_internal.cu.obj,cuiArithmetic_dispatch.cu.obj, andcuCpr_dispatch.cu.objusing the project's full CUDA architecture list.NVCC template-instantiation trace
The parent compile was also rerun with CUDA 13.3's
--ftemplate-backtrace-limit=0. For both host complex types, NVCC emits the complete lookup chain:The same chain is emitted for
cytnx_complex64. After applying only the complex-type mapping, those diagnostics disappear completely, butcudafe++still terminates with0xC0000005; the crashing front end emits no instantiation backtrace for the separatestd::visitfailure.This isolates the type mapping and dispatch rewrite as separate necessary parts of the Windows CUDA compiler workaround.
Linux and macOS
macOS does not compile the
UNI_GPUpath. Linux CUDA compile/tests are the non-Windows regression gate; successful Linuxopenblas-cudaanddebug-openblas-cudabuilds have been reported, and fresh PR checks will run from the new master-based head.Validation
Part of #1114.