Skip to content

Fix CudaCallable type inference never being called - #1048

Merged
inducer merged 1 commit into
inducer:mainfrom
MaxFreedomPollard:fix-cuda-callable-with-types
Sep 11, 2026
Merged

Fix CudaCallable type inference never being called#1048
inducer merged 1 commit into
inducer:mainfrom
MaxFreedomPollard:fix-cuda-callable-with-types

Conversation

@MaxFreedomPollard

Copy link
Copy Markdown
Contributor

CudaCallable spells its type inference method cuda_with_types (loopy/target/cuda.py:148), but the name the callables machinery calls is with_types (loopy/type_inference.py:557). Nothing in the tree references cuda_with_types, so CudaCallable falls through to ScalarCallable.with_types, which raises LoopyError("No type inference information present for the function ...") (loopy/kernel/function_interface.py:677). The method has been unreachable since 438fd1d, the 2018 refactor that moved with_types onto the callables and converted the OpenCL and C siblings without touching loopy/target/cuda.py.

The result is that rsqrt, atan2 and dot cannot be used with CudaTarget. atan2 is a regression against CTarget, which handles it through CMathCallable: CUDACASTBuilder.known_callables (loopy/target/cuda.py:336) overwrites that working entry with the broken CudaCallable("atan2").

Renaming the method to with_types makes four latent errors in it reachable, so this fixes those too. LoopyType has no .kind, so the complex-argument check would have raised AttributeError; it now uses LoopyType.is_complex(). The dot branch returned a bare callable instead of the (callable, clbl_inf_ctx) tuple that every other branch and the base class return, read .fields off the LoopyType rather than off its numpy_dtype, and never set name_in_target. The returned arg_id_to_dtype mappings are now constantdicts, matching OpenCLCallable.with_types and avoiding the deprecation warning in InKernelCallable.__init__.

Generating code for CudaTarget, before and after, with LOOPY_NO_CACHE=1 because loopy's disk cache masks the failure once a working result has been stored:

                              4bf12df                                  this branch
dot, result dtype inferred    LoopyError: No type inference infor...   out[i] = dot(a[i], b[i]);
atan2, float32                LoopyError: No type inference infor...   out[i] = atan2(a[i], b[i]);
atan2, float64                LoopyError: No type inference infor...   out[i] = atan2(a[i], b[i]);
rsqrt, float32                LoopyError: No type inference infor...   out[i] = rsqrt(a[i]);
rsqrt, complex64              LoopyError: No type inference infor...   LoopyTypeError: 'rsqrt' does not support complex arguments.
atan2 with three arguments    LoopyError: No type inference infor...   LoopyError: atan2 can take only 2 arguments.

test_cuda_specific_callables in test/test_target.py covers all six cases. Like test_fma_codegen it needs no device, since CudaTarget only generates code.

Verified on macOS 26.2, Python 3.13.12, numpy 2.4.6, pyopencl 2026.1.4, islpy 2026.2.1:

$ LOOPY_NO_CACHE=1 pytest test/test_target.py -k test_cuda_specific_callables -q
1 passed, 51 deselected                    # this branch
1 failed, 51 deselected                    # loopy/target/cuda.py reverted to 4bf12df, failing at the
                                           # first assertion with LoopyError: No type inference
                                           # information present for the function 'rsqrt'.

$ pytest test/test_target.py -q
11 failed, 37 passed, 4 skipped            # this branch
11 failed, 36 passed, 4 skipped            # 4bf12df

$ pytest test/test_callables.py -q
30 failed, 34 passed                       # this branch, and the same 30 ids on 4bf12df

$ uv run --only-dev ruff check
All checks passed!

$ basedpyright loopy/target/cuda.py test/test_target.py
1 error, 0 warnings, 0 notes               # test/test_target.py:605, scipy.special unresolved, also on 4bf12df

The failing tests in both files come from the only OpenCL platform on this machine, Apple's framework on an M3, which fails at clCreateKernel failed: INVALID_KERNEL. The failing test ids are identical with and without this change.

@inducer

inducer commented Sep 11, 2026

Copy link
Copy Markdown
Owner

Thanks for making this. LGTM! I'll merge it after #1050 goes in.

@inducer

inducer commented Sep 11, 2026

Copy link
Copy Markdown
Owner

FWIW, that bpr failure is spurious and addressed in #1050.

CudaCallable declared its type inference as cuda_with_types, but the
name the callables machinery calls is with_types (loopy/type_inference.py:557).
Nothing in the tree ever referenced cuda_with_types, so CudaCallable fell
back to ScalarCallable.with_types, which raises "No type inference
information present for the function ...". The method has been dead since
the 2018 callables refactor that converted the OpenCL and C siblings
(438fd1d) but skipped cuda.py.

The effect is that rsqrt, atan2 and dot cannot be used with CudaTarget at
all. atan2 is a regression against CTarget, because CUDACASTBuilder.known_callables
replaces the working CMathCallable("atan2") with the broken CudaCallable("atan2").

Rename the method to with_types and repair what reviving it exposes:

- dtype.kind does not exist on LoopyType, use LoopyType.is_complex();
- the "dot" branch returned a bare callable rather than the
  (callable, clbl_inf_ctx) tuple every other branch and the base class
  return, and read .fields off the LoopyType rather than off its
  numpy_dtype;
- "dot" did not set name_in_target;
- the returned arg_id_to_dtype mappings were plain dicts, which
  InKernelCallable.__init__ warns about as deprecated.
@inducer
inducer force-pushed the fix-cuda-callable-with-types branch from fa8816c to 47b705d Compare September 11, 2026 21:26
@inducer
inducer enabled auto-merge (rebase) September 11, 2026 21:26
@inducer
inducer disabled auto-merge September 11, 2026 21:44
@inducer
inducer merged commit 8807bdd into inducer:main Sep 11, 2026
17 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants