Skip to content

Commit a98ddb5

Browse files
committed
Merge branch 'main' into restricted-paths-guard_addl_collaborator_check
2 parents f5aa8a1 + a18022c commit a98ddb5

File tree

10 files changed

+427
-116
lines changed

10 files changed

+427
-116
lines changed

.github/workflows/ci.yml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,15 @@ jobs:
121121
id: filter
122122
if: ${{ startsWith(github.ref_name, 'pull-request/') }}
123123
env:
124-
BASE_REF: ${{ fromJSON(steps.pr-info.outputs.pr-info).base.ref }}
124+
# GitHub Actions evaluates step-level `env:` expressions eagerly —
125+
# the step's `if:` gate does NOT short-circuit them. On non-PR
126+
# events (push/tag/schedule), `pr-info` is skipped and its outputs
127+
# are empty strings, so `fromJSON('')` would raise a template error
128+
# and fail the step despite `if:` being false. Guard the
129+
# `fromJSON` call with a short-circuit so the expression resolves
130+
# to an empty string on non-PR events; the step is still gated
131+
# off by `if:`, so `BASE_REF` is never consumed there.
132+
BASE_REF: ${{ steps.pr-info.outputs.pr-info && fromJSON(steps.pr-info.outputs.pr-info).base.ref || '' }}
125133
run: |
126134
# Diff against the merge base with the PR's actual target branch.
127135
# Uses merge-base so diverged branches only show files changed on

cuda_bindings/cuda/bindings/utils/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
# SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
1+
# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
22
# SPDX-License-Identifier: LicenseRef-NVIDIA-SOFTWARE-LICENSE
33
from typing import Any, Callable
44

5+
from ._nvvm_utils import check_nvvm_compiler_options
56
from ._ptx_utils import get_minimal_required_cuda_ver_from_ptx_ver, get_ptx_ver
67
from ._version_check import warn_if_cuda_major_version_mismatch
78

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2+
# SPDX-License-Identifier: LicenseRef-NVIDIA-SOFTWARE-LICENSE
3+
4+
from typing import Sequence
5+
6+
_PRECHECK_NVVM_IR = """target triple = "nvptx64-unknown-cuda"
7+
target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-i128:128:128-f32:32:32-f64:64:64-v16:16:16-v32:32:32-v64:64:64-v128:128:128-n16:32:64"
8+
9+
define void @dummy_kernel() {{
10+
entry:
11+
ret void
12+
}}
13+
14+
!nvvm.annotations = !{{!0}}
15+
!0 = !{{void ()* @dummy_kernel, !"kernel", i32 1}}
16+
17+
!nvvmir.version = !{{!1}}
18+
!1 = !{{i32 {major}, i32 {minor}, i32 {debug_major}, i32 {debug_minor}}}
19+
"""
20+
21+
22+
def check_nvvm_compiler_options(options: Sequence[str]) -> bool:
23+
"""
24+
Abstracted from https://github.com/NVIDIA/numba-cuda/pull/681
25+
26+
Check if the specified options are supported by the current libNVVM version.
27+
28+
The options are a list of strings, each representing a compiler option.
29+
30+
If the test program fails to compile, the options are not supported and False
31+
is returned.
32+
33+
If the test program compiles successfully, True is returned.
34+
35+
cuda.bindings.nvvm returns exceptions instead of return codes.
36+
37+
Parameters
38+
----------
39+
options : Sequence[str]
40+
List of compiler options as strings (e.g., ["-arch=compute_90", "-g"]).
41+
42+
Returns
43+
-------
44+
bool
45+
True if the options are supported, False otherwise.
46+
47+
Examples
48+
--------
49+
>>> from cuda.bindings.utils import check_nvvm_compiler_options
50+
>>> check_nvvm_compiler_options(["-arch=compute_90", "-g"])
51+
True
52+
"""
53+
try:
54+
from cuda.bindings import nvvm
55+
except ModuleNotFoundError as exc:
56+
if exc.name == "nvvm":
57+
return False
58+
raise
59+
60+
from cuda.bindings._internal.nvvm import _inspect_function_pointer
61+
62+
if _inspect_function_pointer("__nvvmCreateProgram") == 0:
63+
return False
64+
65+
program = nvvm.create_program()
66+
try:
67+
major, minor, debug_major, debug_minor = nvvm.ir_version()
68+
precheck_ir = _PRECHECK_NVVM_IR.format(
69+
major=major,
70+
minor=minor,
71+
debug_major=debug_major,
72+
debug_minor=debug_minor,
73+
)
74+
precheck_ir_bytes = precheck_ir.encode("utf-8")
75+
nvvm.add_module_to_program(
76+
program,
77+
precheck_ir_bytes,
78+
len(precheck_ir_bytes),
79+
"precheck.ll",
80+
)
81+
try:
82+
nvvm.compile_program(program, len(options), options)
83+
except nvvm.nvvmError as e:
84+
if e.status == nvvm.Result.ERROR_INVALID_OPTION:
85+
return False
86+
raise
87+
finally:
88+
nvvm.destroy_program(program)
89+
return True

cuda_bindings/tests/test_utils.py

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,29 @@
1111

1212
from cuda.bindings import driver, runtime
1313
from cuda.bindings._internal.utils import get_c_compiler
14-
from cuda.bindings.utils import get_cuda_native_handle, get_minimal_required_cuda_ver_from_ptx_ver, get_ptx_ver
14+
from cuda.bindings.utils import (
15+
check_nvvm_compiler_options,
16+
get_cuda_native_handle,
17+
get_minimal_required_cuda_ver_from_ptx_ver,
18+
get_ptx_ver,
19+
)
1520

1621
have_cufile = importlib.util.find_spec("cuda.bindings.cufile") is not None
1722

23+
24+
def _is_libnvvm_available() -> bool:
25+
from cuda.bindings._internal.nvvm import _inspect_function_pointer
26+
from cuda.pathfinder import DynamicLibNotFoundError
27+
28+
try:
29+
return _inspect_function_pointer("__nvvmCreateProgram") != 0
30+
except DynamicLibNotFoundError:
31+
return False
32+
33+
34+
_libnvvm_available = _is_libnvvm_available()
35+
_skip_no_libnvvm = pytest.mark.skipif(not _libnvvm_available, reason="libNVVM not available")
36+
1837
ptx_88_kernel = r"""
1938
.version 8.8
2039
.target sm_75
@@ -118,3 +137,35 @@ def test_get_c_compiler():
118137
c_compiler = get_c_compiler()
119138
prefix = ("GCC", "Clang", "MSVC", "Unknown")
120139
assert sum(c_compiler.startswith(p) for p in prefix) == 1
140+
141+
142+
@_skip_no_libnvvm
143+
def test_check_nvvm_compiler_options_valid():
144+
assert check_nvvm_compiler_options(["-arch=compute_90"]) is True
145+
146+
147+
@_skip_no_libnvvm
148+
def test_check_nvvm_compiler_options_invalid():
149+
assert check_nvvm_compiler_options(["--this-is-not-a-valid-option"]) is False
150+
151+
152+
@_skip_no_libnvvm
153+
def test_check_nvvm_compiler_options_empty():
154+
assert check_nvvm_compiler_options([]) is True
155+
156+
157+
@_skip_no_libnvvm
158+
def test_check_nvvm_compiler_options_multiple_valid():
159+
assert check_nvvm_compiler_options(["-arch=compute_90", "-opt=3", "-g"]) is True
160+
161+
162+
@_skip_no_libnvvm
163+
def test_check_nvvm_compiler_options_arch_detection():
164+
assert check_nvvm_compiler_options(["-arch=compute_90"]) is True
165+
assert check_nvvm_compiler_options(["-arch=compute_99999"]) is False
166+
167+
168+
def test_check_nvvm_compiler_options_no_libnvvm():
169+
if _libnvvm_available:
170+
pytest.skip("libNVVM is available; this test targets the fallback path")
171+
assert check_nvvm_compiler_options(["-arch=compute_90"]) is False

cuda_core/cuda/core/__init__.py

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,37 +4,36 @@
44

55
from cuda.core._version import __version__
66

7-
try:
7+
8+
def _import_versioned_module():
9+
import importlib
10+
811
from cuda import bindings
9-
except ImportError:
10-
raise ImportError("cuda.bindings 12.x or 13.x must be installed") from None
11-
else:
12-
cuda_major, cuda_minor = bindings.__version__.split(".")[:2]
12+
13+
cuda_major = bindings.__version__.split(".")[0]
1314
if cuda_major not in ("12", "13"):
1415
raise ImportError("cuda.bindings 12.x or 13.x must be installed")
1516

16-
import importlib
17+
subdir = f"cu{cuda_major}"
18+
try:
19+
versioned_mod = importlib.import_module(f".{subdir}", __package__)
20+
# Import all symbols from the module
21+
globals().update(versioned_mod.__dict__)
22+
except ImportError:
23+
# This is not a wheel build, but a conda or local build, do nothing
24+
pass
25+
26+
27+
_import_versioned_module()
28+
del _import_versioned_module
1729

18-
subdir = f"cu{cuda_major}"
19-
try:
20-
versioned_mod = importlib.import_module(f".{subdir}", __package__)
21-
# Import all symbols from the module
22-
globals().update(versioned_mod.__dict__)
23-
except ImportError:
24-
# This is not a wheel build, but a conda or local build, do nothing
25-
pass
26-
else:
27-
del versioned_mod
28-
finally:
29-
del bindings, importlib, subdir, cuda_major, cuda_minor
3030

3131
from cuda.core import system, utils
3232
from cuda.core._device import Device
3333
from cuda.core._event import Event, EventOptions
3434
from cuda.core._graphics import GraphicsResource
3535
from cuda.core._launch_config import LaunchConfig
3636
from cuda.core._launcher import launch
37-
from cuda.core._layout import _StridedLayout
3837
from cuda.core._linker import Linker, LinkerOptions
3938
from cuda.core._memory import (
4039
Buffer,

cuda_core/cuda/core/_device.pyx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1145,7 +1145,7 @@ class Device:
11451145
from cuda.core._memory import DeviceMemoryResource
11461146
self._memory_resource = DeviceMemoryResource(self._device_id)
11471147
else:
1148-
from cuda.core._memory import _SynchronousMemoryResource
1148+
from cuda.core._memory._legacy import _SynchronousMemoryResource
11491149
self._memory_resource = _SynchronousMemoryResource(self._device_id)
11501150

11511151
return self._memory_resource

cuda_core/cuda/core/_memory/_legacy.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
1+
# SPDX-FileCopyrightText: Copyright (c) 2024-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
22
#
33
# SPDX-License-Identifier: Apache-2.0
44

@@ -17,7 +17,7 @@
1717
driver,
1818
)
1919

20-
__all__ = ["LegacyPinnedMemoryResource", "_SynchronousMemoryResource"]
20+
__all__ = ["LegacyPinnedMemoryResource"]
2121

2222

2323
class LegacyPinnedMemoryResource(MemoryResource):

cuda_core/tests/test_launcher.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
ProgramOptions,
2525
launch,
2626
)
27-
from cuda.core._memory import _SynchronousMemoryResource
27+
from cuda.core._memory._legacy import _SynchronousMemoryResource
2828
from cuda.core._utils.cuda_utils import CUDAError
2929

3030

0 commit comments

Comments
 (0)