Coverage for cuda/core/_linker.pyx: 66.67%

426 statements  

« prev     ^ index     » next       coverage.py v7.17.2, created at 2026-11-05 01:11 +0000

1# SPDX-FileCopyrightText: Copyright (c) 2024-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 

2# 

3# SPDX-License-Identifier: Apache-2.0 

4"""Linking machinery for combining object codes. 

5  

6This module provides :class:`Linker` for linking one or more 

7:class:`~cuda.core.ObjectCode` objects, with :class:`LinkerOptions` for 

8configuration. 

9""" 

10  

11from __future__ import annotations 

12  

13from cpython.bytearray cimport PyByteArray_AS_STRING 

14from libc.stdint cimport intptr_t, uint32_t 

15from libcpp.vector cimport vector 

16from cuda.bindings cimport cydriver 

17from cuda.bindings cimport cynvjitlink 

18  

19from ._rt cimport ( 

20 as_cu, 

21 as_py, 

22 create_culink_handle, 

23 create_nvjitlink_handle, 

24) 

25from cuda.core._utils.cuda_utils cimport HANDLE_RETURN, HANDLE_RETURN_NVJITLINK 

26  

27import sys 

28from dataclasses import dataclass 

29from typing import TYPE_CHECKING, Union 

30from warnings import warn 

31  

32from cuda.pathfinder import DynamicLibNotFoundError 

33from cuda.bindings import nvjitlink as _nvjitlink_bindings 

34from cuda.core._device import Device 

35from cuda.core._module import ObjectCode 

36from cuda.core._utils.clear_error_support import assert_type 

37from cuda.core._utils.cuda_utils import ( 

38 CUDAError, 

39 check_or_create_options, 

40 driver, 

41 is_sequence, 

42) 

43from cuda.core.typing import CompilerBackendType, ObjectCodeFormatType 

44  

45if TYPE_CHECKING: 

46 import cuda.bindings.driver # no-cython-lint 

47 import cuda.bindings.nvjitlink # no-cython-lint 

48  

49# Module-level annotations to ensure stubgen-pyx keeps the above imports in 

50# the generated `.pyi` so that the LinkerHandleT forward references resolve. 

51# These names are not assigned, so they only affect __annotations__. 

52_keep_driver_in_stub: "cuda.bindings.driver.CUlinkState" 

53_keep_nvjitlink_in_stub: "cuda.bindings.nvjitlink.nvJitLinkHandle" 

54  

55ctypedef const char* const_char_ptr 

56  

57__all__ = ["Linker", "LinkerOptions"] 

58  

59LinkerHandleT = Union["cuda.bindings.nvjitlink.nvJitLinkHandle", "cuda.bindings.driver.CUlinkState"] 

60  

61  

62# ============================================================================= 

63# Principal class 

64# ============================================================================= 

65  

66  

67cdef inline int Linker_check_open(Linker self) except -1: 

68 if self.is_closed: 1nbq0eaXzVALMBNCOuvoPQRSTUDwEFxGWH2IpyfYZ1JKrstgchijkldm

69 raise RuntimeError("Linker has been closed") 1n

70 return 0 1nbq0eaXzVALMBNCOuvoPQRSTUDwEFxGWH2IpyfYZ1JKrstgchijkldm

71  

72  

73cdef class Linker: 

74 """Represent a linking machinery to link one or more object codes into 

75 :class:`~cuda.core.ObjectCode`. 

76  

77 This object provides a unified interface to multiple underlying 

78 linker libraries (such as nvJitLink or cuLink* from the CUDA driver). 

79  

80 Parameters 

81 ---------- 

82 object_codes : :class:`~cuda.core.ObjectCode` 

83 One or more ObjectCode objects to be linked. 

84 options : :class:`LinkerOptions`, optional 

85 Options for the linker. If not provided, default options will be used. 

86 """ 

87  

88 def __init__(self, *object_codes: ObjectCode, options: LinkerOptions | None = None): 

89 Linker_init(self, object_codes, options) 2n b q Tb0 e a 1bX z 4 V A L M B N C O u v o P Q R S T U D w E F x G W 6 H 2 I p y f Y Z 1 J K 3 r s t g c h i j k l d m

90  

91 @property 

92 def is_closed(self) -> bool: 

93 """Whether this linker has been closed.""" 

94 if self._use_nvjitlink: 1nbq0eaXzVALMBNCOuvoPQRSTUDwEFxGWH2IpyfYZ1JKrstgchijkldm

95 return self._nvjitlink_handle.get() == NULL 1nbq0eaXzVALMBNCOuvoPQRSTUDwEFxGWH2IpyfYZ1JKrstgchijkldm

96 return self._culink_handle.get() == NULL 

97  

98 def link(self, target_type: ObjectCodeFormatType | str) -> ObjectCode: 

99 """Link the provided object codes into a single output of the specified target type. 

100  

101 Parameters 

102 ---------- 

103 target_type : ObjectCodeFormatType | str 

104 The type of the target output. Must be "cubin", "ptx", or 

105 "ltoir". Linked LTOIR output requires 

106 ``link_time_optimization=True`` and nvJitLink 13.3 or newer. 

107  

108 Returns 

109 ------- 

110 :class:`~cuda.core.ObjectCode` 

111 The linked object code of the specified target type. 

112  

113 .. note:: 

114  

115 Ensure that input object codes were compiled with appropriate 

116 flags for linking (e.g., relocatable device code enabled). 

117  

118 A CUBIN produced with ``incremental=True`` can be passed directly 

119 to another :class:`Linker`, but it can still contain unresolved 

120 device references and should be finalized before execution. 

121  

122 ``"ltoir"`` output contains only the LTOIR carried by the inputs. 

123 Direct PTX and CUBIN inputs are rejected because they carry no 

124 LTOIR. FATBIN, host object, and library inputs are accepted but 

125 may carry no LTOIR, in which case they contribute nothing to the 

126 output. 

127 """ 

128 Linker_check_open(self) 1nbq0eaXzVALMBNCOuvoPQRSTUDwEFxGWH2IpyfYZ1JKrstgchijkldm

129 return Linker_link(self, str(target_type)) 1nbq0eaXzVALMBNCOuvoPQRSTUDwEFxGWH2IpyfYZ1JKrstgchijkldm

130  

131 def get_error_log(self) -> str: 

132 """Get the error log generated by the linker. 

133  

134 Returns 

135 ------- 

136 str 

137 The error log. 

138 """ 

139 # After link(), the decoded log is cached here. 

140 if self._error_log is not None: 1nbqeaXzVALMBNCOuvoPQRSTUDwEFxGWHIpyfJKrstgchijkldm

141 return self._error_log 1ny

142 Linker_check_open(self) 1nbqeaXzVALMBNCOuvoPQRSTUDwEFxGWHIpyfJKrstgchijkldm

143 cdef cynvjitlink.nvJitLinkHandle c_h 

144 cdef size_t c_log_size = 0 1nbqeaXzVALMBNCOuvoPQRSTUDwEFxGWHIpyfJKrstgchijkldm

145 cdef char* c_log_ptr 

146 if self._use_nvjitlink: 1nbqeaXzVALMBNCOuvoPQRSTUDwEFxGWHIpyfJKrstgchijkldm

147 c_h = as_cu(self._nvjitlink_handle) 1nbqeaXzVALMBNCOuvoPQRSTUDwEFxGWHIpyfJKrstgchijkldm

148 HANDLE_RETURN_NVJITLINK(c_h, cynvjitlink.nvJitLinkGetErrorLogSize(c_h, &c_log_size)) 1nbqeaXzVALMBNCOuvoPQRSTUDwEFxGWHIpyfJKrstgchijkldm

149 log = bytearray(c_log_size) 1nbqeaXzVALMBNCOuvoPQRSTUDwEFxGWHIpyfJKrstgchijkldm

150 if c_log_size > 0: 1nbqeaXzVALMBNCOuvoPQRSTUDwEFxGWHIpyfJKrstgchijkldm

151 c_log_ptr = <char*>(<bytearray>log) 1X

152 HANDLE_RETURN_NVJITLINK(c_h, cynvjitlink.nvJitLinkGetErrorLog(c_h, c_log_ptr)) 1X

153 return log.decode("utf-8", errors="backslashreplace") 1nbqeaXzVALMBNCOuvoPQRSTUDwEFxGWHIpyfJKrstgchijkldm

154 else: 

155 return (<bytearray>self._drv_log_bufs[2]).decode( 

156 "utf-8", errors="backslashreplace").rstrip('\x00') 

157  

158 def get_info_log(self) -> str: 

159 """Get the info log generated by the linker. 

160  

161 Returns 

162 ------- 

163 str 

164 The info log. 

165 """ 

166 # After link(), the decoded log is cached here. 

167 if self._info_log is not None: 1nbqeazVALMBNCOuvoPQRSTUDwEFxGWHIpyfJKrstgchijkldm

168 return self._info_log 1nzy

169 Linker_check_open(self) 1nbqeazVALMBNCOuvoPQRSTUDwEFxGWHIpyfJKrstgchijkldm

170 cdef cynvjitlink.nvJitLinkHandle c_h 

171 cdef size_t c_log_size = 0 1nbqeazVALMBNCOuvoPQRSTUDwEFxGWHIpyfJKrstgchijkldm

172 cdef char* c_log_ptr 

173 if self._use_nvjitlink: 1nbqeazVALMBNCOuvoPQRSTUDwEFxGWHIpyfJKrstgchijkldm

174 c_h = as_cu(self._nvjitlink_handle) 1nbqeazVALMBNCOuvoPQRSTUDwEFxGWHIpyfJKrstgchijkldm

175 HANDLE_RETURN_NVJITLINK(c_h, cynvjitlink.nvJitLinkGetInfoLogSize(c_h, &c_log_size)) 1nbqeazVALMBNCOuvoPQRSTUDwEFxGWHIpyfJKrstgchijkldm

176 log = bytearray(c_log_size) 1nbqeazVALMBNCOuvoPQRSTUDwEFxGWHIpyfJKrstgchijkldm

177 if c_log_size > 0: 1nbqeazVALMBNCOuvoPQRSTUDwEFxGWHIpyfJKrstgchijkldm

178 c_log_ptr = <char*>(<bytearray>log) 1beaABCuopfcd

179 HANDLE_RETURN_NVJITLINK(c_h, cynvjitlink.nvJitLinkGetInfoLog(c_h, c_log_ptr)) 1beaABCuopfcd

180 return log.decode("utf-8", errors="backslashreplace") 1nbqeazVALMBNCOuvoPQRSTUDwEFxGWHIpyfJKrstgchijkldm

181 else: 

182 return (<bytearray>self._drv_log_bufs[0]).decode( 

183 "utf-8", errors="backslashreplace").rstrip('\x00') 

184  

185 def close(self) -> None: 

186 """Destroy this linker.""" 

187 cdef vector[cydriver.CUjit_option] empty_keys 

188 cdef vector[void*] empty_values 

189 if self._use_nvjitlink: 1n3gchijkldm

190 self._nvjitlink_handle.reset() 1n3gchijkldm

191 else: 

192 if self._drv_log_bufs is not None: 

193 if self._info_log is None: 

194 self._info_log = self.get_info_log() 

195 if self._error_log is None: 

196 self._error_log = self.get_error_log() 

197 # Destroy the CUlinkState before releasing storage referenced by it. 

198 self._culink_handle.reset() 

199 self._drv_jit_keys.swap(empty_keys) 

200 self._drv_jit_values.swap(empty_values) 

201 self._drv_log_bufs = None 

202  

203 @property 

204 def handle(self) -> LinkerHandleT: 

205 """Return the underlying handle object. 

206  

207 .. note:: 

208  

209 The type of the returned object depends on the backend. 

210  

211 .. caution:: 

212  

213 This handle is a Python object. To get the memory address of the underlying C 

214 handle, call ``int(Linker.handle)``. 

215 """ 

216 if self._use_nvjitlink: 143

217 return as_py(self._nvjitlink_handle) 143

218 else: 

219 return as_py(self._culink_handle) 

220  

221 @classmethod 

222 def which_backend(cls) -> CompilerBackendType: 

223 """Return which linking backend will be used. 

224  

225 Returns :attr:`~CompilerBackendType.NVJITLINK` when the nvJitLink 

226 library is available and meets the minimum version requirement, 

227 otherwise :attr:`~CompilerBackendType.DRIVER`. 

228  

229 .. note:: 

230  

231 Prefer letting :class:`Linker` decide. Query ``which_backend()`` 

232 only when you need to dispatch based on input format (for 

233 example: choose PTX vs. LTOIR before constructing a 

234 ``Linker``). The returned value names an implementation 

235 detail whose support matrix may shift across CTK releases. 

236 """ 

237 return CompilerBackendType.DRIVER if _decide_nvjitlink_or_driver() else CompilerBackendType.NVJITLINK 2UbQbPb_b2b3bV A L M B N C O u v o P Q R S T U D w E F x G W 3 r s t g c h i j k l d m

238  

239  

240# ============================================================================= 

241# Supporting classes 

242# ============================================================================= 

243  

244@dataclass 

245class LinkerOptions: 

246 """Customizable options for configuring :class:`Linker`. 

247  

248 Since the linker may choose to use nvJitLink or the driver APIs as the linking backend, 

249 not all options are applicable. When the system's installed nvJitLink is too old (<12.3), 

250 or not installed, the driver APIs (cuLink) will be used instead. 

251  

252 Attributes 

253 ---------- 

254 name : str, optional 

255 Name of the linker. If the linking succeeds, the name is passed down to the generated :class:`ObjectCode`. 

256 arch : str, optional 

257 Pass the SM architecture value, such as ``sm_<CC>`` (for generating CUBIN) or 

258 ``compute_<CC>`` (for generating PTX). If not provided, the current device's architecture 

259 will be used. 

260 max_register_count : int, optional 

261 Maximum register count. 

262 time : bool, optional 

263 Print timing information to the info log. 

264 Default: False. 

265 verbose : bool, optional 

266 Print verbose messages to the info log. 

267 Default: False. 

268 link_time_optimization : bool, optional 

269 Perform link time optimization. 

270 Default: False. 

271 incremental : bool, optional 

272 Perform an incremental link. The result can be passed 

273 directly to a later :class:`Linker`. Requires nvJitLink 13.2 or newer 

274 and is not supported by the driver linker backend. Intermediate 

275 caching is disabled on nvJitLink versions older than 13.6 when combined 

276 with link-time optimization, to work around an nvJitLink bug. 

277 Default: False. 

278 ptx : bool, optional 

279 Emit PTX after linking instead of CUBIN; only supported with ``link_time_optimization=True``. 

280 Default: False. 

281 optimization_level : int, optional 

282 Set optimization level. Only 0 and 3 are accepted. 

283 debug : bool, optional 

284 Generate debug information. 

285 Default: False. 

286 lineinfo : bool, optional 

287 Generate line information. 

288 Default: False. 

289 ftz : bool, optional 

290 Flush denormal values to zero. 

291 Default: False. 

292 prec_div : bool, optional 

293 Use precise division. 

294 Default: True. 

295 prec_sqrt : bool, optional 

296 Use precise square root. 

297 Default: True. 

298 fma : bool, optional 

299 Use fast multiply-add. 

300 Default: True. 

301 kernels_used : [str | tuple[str] | list[str]], optional 

302 Pass a kernel or sequence of kernels that are used; any not in the list can be removed. 

303 variables_used : [str | tuple[str] | list[str]], optional 

304 Pass a variable or sequence of variables that are used; any not in the list can be removed. 

305 optimize_unused_variables : bool, optional 

306 Assume that if a variable is not referenced in device code, it can be removed. 

307 Default: False. 

308 ptxas_options : [str | tuple[str] | list[str]], optional 

309 Pass options to PTXAS. 

310 split_compile : int, optional 

311 Split compilation maximum thread count. Use 0 to use all available processors. Value of 1 disables split 

312 compilation (default). 

313 Default: 1. 

314 split_compile_extended : int, optional 

315 A more aggressive form of split compilation available in LTO mode only. Accepts a maximum thread count value. 

316 Use 0 to use all available processors. Value of 1 disables extended split compilation (default). Note: This 

317 option can potentially impact performance of the compiled binary. 

318 Default: 1. 

319 no_cache : bool, optional 

320 Do not cache the intermediate steps of nvJitLink. 

321 Caching is also disabled automatically for incremental links that use 

322 link-time optimization on nvJitLink versions older than 13.6, to work 

323 around an nvJitLink bug. 

324 Default: False. 

325 numba_debug : bool, optional 

326 Non-functional. ``numba_debug`` is an NVVM/NVRTC *compiler* option; 

327 neither nvJitLink nor the driver's cuLink API recognizes it, so no 

328 linking backend can honor it and the value is ignored. 

329 Default: None. 

330  

331 .. deprecated:: 1.2.0 

332 Setting this option emits a :class:`DeprecationWarning`. It has never 

333 had an effect on any linking backend and will be removed in 

334 ``cuda.core`` 2.0.0. Use 

335 :attr:`ProgramOptions.numba_debug` on an NVVM or NVRTC compilation 

336 path instead. 

337 """ 

338  

339 name: str | None = "<default linker>" 

340 arch: str | None = None 

341 max_register_count: int | None = None 

342 time: bool | None = None 

343 verbose: bool | None = None 

344 link_time_optimization: bool | None = None 

345 ptx: bool | None = None 

346 optimization_level: int | None = None 

347 debug: bool | None = None 

348 lineinfo: bool | None = None 

349 ftz: bool | None = None 

350 prec_div: bool | None = None 

351 prec_sqrt: bool | None = None 

352 fma: bool | None = None 

353 kernels_used: str | tuple[str] | list[str] | None = None 

354 variables_used: str | tuple[str] | list[str] | None = None 

355 optimize_unused_variables: bool | None = None 

356 ptxas_options: str | tuple[str] | list[str] | None = None 

357 split_compile: int | None = None 

358 split_compile_extended: int | None = None 

359 no_cache: bool | None = None 

360 numba_debug: bool | None = None 

361 incremental: bool | None = None 

362  

363 def __post_init__(self) -> None: 

364 _lazy_init() 2LbWbn b q Tb0 e a X z 4 6 H 2 I p y f YbZb8 qbrb[ sbtbubvb] ^ _ ` { | } ~ 9 ! % ' wbxbybzbabbbcbdbebfbgbhb# $ ( ) AbBbCbDbibjbkblbmbnbobpb* + , - IbY Z 1 7 KbFbGb5 . / : ; = ? @ NbObMbJbHbEbJ K 3 r s t g c h i j k l d m

365 self._name = self.name.encode() 2LbWbn b q Tb0 e a X z 4 6 H 2 I p y f YbZb8 qbrb[ sbtbubvb] ^ _ ` { | } ~ 9 ! % ' wbxbybzbabbbcbdbebfbgbhb# $ ( ) AbBbCbDbibjbkblbmbnbobpb* + , - IbY Z 1 7 KbFbGb5 . / : ; = ? @ NbObMbJbHbEbJ K 3 r s t g c h i j k l d m

366 # No linking backend reads ``numba_debug``, so warn where the value is 

367 # supplied rather than in the option builders -- the user learns once, 

368 # at the call site that set it, instead of once per link. The gate is 

369 # ``is not None`` (unlike the ignore-warning on the PTX compile path): 

370 # it is the *field* that is going away, so any explicit value earns the 

371 # notice, including ``False``. 

372 if self.numba_debug is not None: 2LbWbn b q Tb0 e a X z 4 6 H 2 I p y f YbZb8 qbrb[ sbtbubvb] ^ _ ` { | } ~ 9 ! % ' wbxbybzbabbbcbdbebfbgbhb# $ ( ) AbBbCbDbibjbkblbmbnbobpb* + , - IbY Z 1 7 KbFbGb5 . / : ; = ? @ NbObMbJbHbEbJ K 3 r s t g c h i j k l d m

373 warn( 27 FbGb

374 "numba_debug is not supported by any linking backend and is ignored. " 

375 "LinkerOptions.numba_debug is deprecated and will be removed in " 

376 "cuda.core 2.0.0; use ProgramOptions.numba_debug on an NVVM or NVRTC " 

377 "compilation path instead.", 

378 DeprecationWarning, 27 FbGb

379 stacklevel=3, 

380 ) 

381  

382 def _prepare_nvjitlink_options(self, as_bytes: bool = False) -> list[bytes] | list[str]: 

383 options = [] 2n b q 0 e a X z 4 V A L M B N C O u v o P Q R S T U D w E F x G W 6 H 2 I p y f 8 qbrb[ sbtbubvb] ^ _ ` { | } ~ 9 ! % ' wbxbybzbabbbcbdbebfbgbhb# $ ( ) AbBbCbDbibjbkblbmbnbobpb* + , - IbY Z 1 KbFbGbJ K 3 r s t g c h i j k l d m

384  

385 if self.arch is not None: 2n b q 0 e a X z 4 V A L M B N C O u v o P Q R S T U D w E F x G W 6 H 2 I p y f 8 qbrb[ sbtbubvb] ^ _ ` { | } ~ 9 ! % ' wbxbybzbabbbcbdbebfbgbhb# $ ( ) AbBbCbDbibjbkblbmbnbobpb* + , - IbY Z 1 KbFbGbJ K 3 r s t g c h i j k l d m

386 options.append(f"-arch={self.arch}") 2n b q 0 e a X z 4 A L M B N C O u v o P Q R S T U D w E F x G W 6 H 2 I p y f 8 qbrb[ sbtbubvb] ^ _ ` { | } ~ 9 ! % ' wbxbybzbabbbcbdbebfbgbhb# $ ( ) AbBbCbDbibjbkblbmbnbobpb* + , - IbY Z 1 KbFbGbJ K 3 r s t g c h i j k l d m

387 else: 

388 options.append("-arch=sm_" + "".join(f"{i}" for i in Device().compute_capability)) 1V

389 if self.max_register_count is not None: 2n b q 0 e a X z 4 V A L M B N C O u v o P Q R S T U D w E F x G W 6 H 2 I p y f 8 qbrb[ sbtbubvb] ^ _ ` { | } ~ 9 ! % ' wbxbybzbabbbcbdbebfbgbhb# $ ( ) AbBbCbDbibjbkblbmbnbobpb* + , - IbY Z 1 KbFbGbJ K 3 r s t g c h i j k l d m

390 options.append(f"-maxrregcount={self.max_register_count}") 1L8g

391 if self.time is not None: 2n b q 0 e a X z 4 V A L M B N C O u v o P Q R S T U D w E F x G W 6 H 2 I p y f 8 qbrb[ sbtbubvb] ^ _ ` { | } ~ 9 ! % ' wbxbybzbabbbcbdbebfbgbhb# $ ( ) AbBbCbDbibjbkblbmbnbobpb* + , - IbY Z 1 KbFbGbJ K 3 r s t g c h i j k l d m

392 options.append("-time") 1Cd

393 if self.verbose: 2n b q 0 e a X z 4 V A L M B N C O u v o P Q R S T U D w E F x G W 6 H 2 I p y f 8 qbrb[ sbtbubvb] ^ _ ` { | } ~ 9 ! % ' wbxbybzbabbbcbdbebfbgbhb# $ ( ) AbBbCbDbibjbkblbmbnbobpb* + , - IbY Z 1 KbFbGbJ K 3 r s t g c h i j k l d m

394 options.append("-verbose") 1A

395 if self.link_time_optimization: 2n b q 0 e a X z 4 V A L M B N C O u v o P Q R S T U D w E F x G W 6 H 2 I p y f 8 qbrb[ sbtbubvb] ^ _ ` { | } ~ 9 ! % ' wbxbybzbabbbcbdbebfbgbhb# $ ( ) AbBbCbDbibjbkblbmbnbobpb* + , - IbY Z 1 KbFbGbJ K 3 r s t g c h i j k l d m

396 options.append("-lto") 2b e a p f ] ^ _ ` 9 ! % ' abbbcbdb# $ ( ) ibjbkblb* + , - Y Z

397 if self.incremental: 2n b q 0 e a X z 4 V A L M B N C O u v o P Q R S T U D w E F x G W 6 H 2 I p y f 8 qbrb[ sbtbubvb] ^ _ ` { | } ~ 9 ! % ' wbxbybzbabbbcbdbebfbgbhb# $ ( ) AbBbCbDbibjbkblbmbnbobpb* + , - IbY Z 1 KbFbGbJ K 3 r s t g c h i j k l d m

398 options.append("-r") 2q 0 e a [ { | } ~ 9 ! % ' ebfbgbhb# $ ( ) mbnbobpb* + , - Y Z

399 if self.ptx: 2n b q 0 e a X z 4 V A L M B N C O u v o P Q R S T U D w E F x G W 6 H 2 I p y f 8 qbrb[ sbtbubvb] ^ _ ` { | } ~ 9 ! % ' wbxbybzbabbbcbdbebfbgbhb# $ ( ) AbBbCbDbibjbkblbmbnbobpb* + , - IbY Z 1 KbFbGbJ K 3 r s t g c h i j k l d m

400 options.append("-ptx") 16p

401 if self.optimization_level is not None: 2n b q 0 e a X z 4 V A L M B N C O u v o P Q R S T U D w E F x G W 6 H 2 I p y f 8 qbrb[ sbtbubvb] ^ _ ` { | } ~ 9 ! % ' wbxbybzbabbbcbdbebfbgbhb# $ ( ) AbBbCbDbibjbkblbmbnbobpb* + , - IbY Z 1 KbFbGbJ K 3 r s t g c h i j k l d m

402 options.append(f"-O{self.optimization_level}") 1M

403 if self.debug: 2n b q 0 e a X z 4 V A L M B N C O u v o P Q R S T U D w E F x G W 6 H 2 I p y f 8 qbrb[ sbtbubvb] ^ _ ` { | } ~ 9 ! % ' wbxbybzbabbbcbdbebfbgbhb# $ ( ) AbBbCbDbibjbkblbmbnbobpb* + , - IbY Z 1 KbFbGbJ K 3 r s t g c h i j k l d m

404 options.append("-g") 2B 8 IbKbFbGbc

405 if self.lineinfo: 2n b q 0 e a X z 4 V A L M B N C O u v o P Q R S T U D w E F x G W 6 H 2 I p y f 8 qbrb[ sbtbubvb] ^ _ ` { | } ~ 9 ! % ' wbxbybzbabbbcbdbebfbgbhb# $ ( ) AbBbCbDbibjbkblbmbnbobpb* + , - IbY Z 1 KbFbGbJ K 3 r s t g c h i j k l d m

406 options.append("-lineinfo") 2N Ibh

407 if self.ftz is not None: 2n b q 0 e a X z 4 V A L M B N C O u v o P Q R S T U D w E F x G W 6 H 2 I p y f 8 qbrb[ sbtbubvb] ^ _ ` { | } ~ 9 ! % ' wbxbybzbabbbcbdbebfbgbhb# $ ( ) AbBbCbDbibjbkblbmbnbobpb* + , - IbY Z 1 KbFbGbJ K 3 r s t g c h i j k l d m

408 options.append(f"-ftz={'1' if self.ftz else '0'}") 1Rf8i

409 if self.prec_div is not None: 2n b q 0 e a X z 4 V A L M B N C O u v o P Q R S T U D w E F x G W 6 H 2 I p y f 8 qbrb[ sbtbubvb] ^ _ ` { | } ~ 9 ! % ' wbxbybzbabbbcbdbebfbgbhb# $ ( ) AbBbCbDbibjbkblbmbnbobpb* + , - IbY Z 1 KbFbGbJ K 3 r s t g c h i j k l d m

410 options.append(f"-prec-div={'1' if self.prec_div else '0'}") 1Sfj

411 if self.prec_sqrt is not None: 2n b q 0 e a X z 4 V A L M B N C O u v o P Q R S T U D w E F x G W 6 H 2 I p y f 8 qbrb[ sbtbubvb] ^ _ ` { | } ~ 9 ! % ' wbxbybzbabbbcbdbebfbgbhb# $ ( ) AbBbCbDbibjbkblbmbnbobpb* + , - IbY Z 1 KbFbGbJ K 3 r s t g c h i j k l d m

412 options.append(f"-prec-sqrt={'1' if self.prec_sqrt else '0'}") 1Tfk

413 if self.fma is not None: 2n b q 0 e a X z 4 V A L M B N C O u v o P Q R S T U D w E F x G W 6 H 2 I p y f 8 qbrb[ sbtbubvb] ^ _ ` { | } ~ 9 ! % ' wbxbybzbabbbcbdbebfbgbhb# $ ( ) AbBbCbDbibjbkblbmbnbobpb* + , - IbY Z 1 KbFbGbJ K 3 r s t g c h i j k l d m

414 options.append(f"-fma={'1' if self.fma else '0'}") 1Ufl

415 if self.kernels_used is not None: 2n b q 0 e a X z 4 V A L M B N C O u v o P Q R S T U D w E F x G W 6 H 2 I p y f 8 qbrb[ sbtbubvb] ^ _ ` { | } ~ 9 ! % ' wbxbybzbabbbcbdbebfbgbhb# $ ( ) AbBbCbDbibjbkblbmbnbobpb* + , - IbY Z 1 KbFbGbJ K 3 r s t g c h i j k l d m

416 if isinstance(self.kernels_used, str): 1DwE

417 options.append(f"-kernels-used={self.kernels_used}") 1D

418 elif isinstance(self.kernels_used, list): 1wE

419 for kernel in self.kernels_used: 1w

420 options.append(f"-kernels-used={kernel}") 1w

421 if self.variables_used is not None: 2n b q 0 e a X z 4 V A L M B N C O u v o P Q R S T U D w E F x G W 6 H 2 I p y f 8 qbrb[ sbtbubvb] ^ _ ` { | } ~ 9 ! % ' wbxbybzbabbbcbdbebfbgbhb# $ ( ) AbBbCbDbibjbkblbmbnbobpb* + , - IbY Z 1 KbFbGbJ K 3 r s t g c h i j k l d m

422 if isinstance(self.variables_used, str): 1FxG

423 options.append(f"-variables-used={self.variables_used}") 1F

424 elif isinstance(self.variables_used, list): 1xG

425 for variable in self.variables_used: 1x

426 options.append(f"-variables-used={variable}") 1x

427 if self.optimize_unused_variables is not None: 2n b q 0 e a X z 4 V A L M B N C O u v o P Q R S T U D w E F x G W 6 H 2 I p y f 8 qbrb[ sbtbubvb] ^ _ ` { | } ~ 9 ! % ' wbxbybzbabbbcbdbebfbgbhb# $ ( ) AbBbCbDbibjbkblbmbnbobpb* + , - IbY Z 1 KbFbGbJ K 3 r s t g c h i j k l d m

428 options.append("-optimize-unused-variables") 1O

429 if self.ptxas_options is not None: 2n b q 0 e a X z 4 V A L M B N C O u v o P Q R S T U D w E F x G W 6 H 2 I p y f 8 qbrb[ sbtbubvb] ^ _ ` { | } ~ 9 ! % ' wbxbybzbabbbcbdbebfbgbhb# $ ( ) AbBbCbDbibjbkblbmbnbobpb* + , - IbY Z 1 KbFbGbJ K 3 r s t g c h i j k l d m

430 if isinstance(self.ptxas_options, str): 1uvo

431 options.append(f"-Xptxas={self.ptxas_options}") 1u

432 elif is_sequence(self.ptxas_options): 1vo

433 for opt in self.ptxas_options: 1vo

434 options.append(f"-Xptxas={opt}") 1vo

435 if self.split_compile is not None: 2n b q 0 e a X z 4 V A L M B N C O u v o P Q R S T U D w E F x G W 6 H 2 I p y f 8 qbrb[ sbtbubvb] ^ _ ` { | } ~ 9 ! % ' wbxbybzbabbbcbdbebfbgbhb# $ ( ) AbBbCbDbibjbkblbmbnbobpb* + , - IbY Z 1 KbFbGbJ K 3 r s t g c h i j k l d m

436 options.append(f"-split-compile={int(self.split_compile)}") 1Pm

437 if self.split_compile_extended is not None: 2n b q 0 e a X z 4 V A L M B N C O u v o P Q R S T U D w E F x G W 6 H 2 I p y f 8 qbrb[ sbtbubvb] ^ _ ` { | } ~ 9 ! % ' wbxbybzbabbbcbdbebfbgbhb# $ ( ) AbBbCbDbibjbkblbmbnbobpb* + , - IbY Z 1 KbFbGbJ K 3 r s t g c h i j k l d m

438 options.append(f"-split-compile-extended={int(self.split_compile_extended)}") 1Q

439 # nvbugs 6659652 

440 if self.no_cache is True or ( 2n b q 0 e a X z 4 V A L M B N C O u v o P Q R S T U D w E F x G W 6 H 2 I p y f 8 qbrb[ sbtbubvb] ^ _ ` { | } ~ 9 ! % ' wbxbybzbabbbcbdbebfbgbhb# $ ( ) AbBbCbDbibjbkblbmbnbobpb* + , - IbY Z 1 KbFbGbJ K 3 r s t g c h i j k l d m

441 _nvjitlink_version < (13, 6) and self.incremental and self.link_time_optimization 2n b q 0 e a X z 4 V A L M B N C O u v o P Q R S T U D w E F x G 6 H 2 I p y f 8 qbrb[ sbtbubvb] ^ _ ` { | } ~ 9 ! % ' wbxbybzbabbbcbdbebfbgbhb# $ ( ) IbY Z 1 KbFbGbJ K 3 r s t g c h i j k l d m

442 ): 

443 options.append("-no-cache") 2e a W 9 ! # $ AbBbCbDbibjbkblbmbnbobpb* + , - Y Z

444  

445 if as_bytes: 2n b q 0 e a X z 4 V A L M B N C O u v o P Q R S T U D w E F x G W 6 H 2 I p y f 8 qbrb[ sbtbubvb] ^ _ ` { | } ~ 9 ! % ' wbxbybzbabbbcbdbebfbgbhb# $ ( ) AbBbCbDbibjbkblbmbnbobpb* + , - IbY Z 1 KbFbGbJ K 3 r s t g c h i j k l d m

446 return [o.encode() for o in options] 2n b q 0 e a X z 4 V A L M B N C O u v o P Q R S T U D w E F x G W 6 H 2 I p y f 8 qbrb[ sbtbubvb] ^ _ ` { | } ~ 9 ! % ' wbxbybzbabbbcbdbebfbgbhb# $ ( ) AbBbCbDbibjbkblbmbnbobpb* + , - Y Z 1 KbFbGbJ K 3 r s t g c h i j k l d m

447 else: 

448 return options 2Ib

449  

450 def _prepare_driver_options(self) -> tuple[list[object], list[object]]: 

451 formatted_options = [] 27 5 . / : ; = ? @ NbObMbJbHbEb

452 option_keys = [] 27 5 . / : ; = ? @ NbObMbJbHbEb

453  

454 # allocate a fixed-sized buffer for each info/error log 

455 size = 4194304 27 5 . / : ; = ? @ NbObMbJbHbEb

456 formatted_options.extend((bytearray(size), size, bytearray(size), size)) 27 5 . / : ; = ? @ NbObMbJbHbEb

457 option_keys.extend( 27 5 . / : ; = ? @ NbObMbJbHbEb

458 ( 

459 _driver.CUjit_option.CU_JIT_INFO_LOG_BUFFER, 27 5 . / : ; = ? @ NbObMbJbHbEb

460 _driver.CUjit_option.CU_JIT_INFO_LOG_BUFFER_SIZE_BYTES, 27 5 . / : ; = ? @ NbObMbJbHbEb

461 _driver.CUjit_option.CU_JIT_ERROR_LOG_BUFFER, 27 5 . / : ; = ? @ NbObMbJbHbEb

462 _driver.CUjit_option.CU_JIT_ERROR_LOG_BUFFER_SIZE_BYTES, 27 5 . / : ; = ? @ NbObMbJbHbEb

463 ) 

464 ) 

465  

466 if self.arch is not None: 27 5 . / : ; = ? @ NbObMbJbHbEb

467 arch = self.arch.split("_")[-1].upper() 175

468 formatted_options.append(getattr(_driver.CUjit_target, f"CU_TARGET_COMPUTE_{arch}")) 175

469 option_keys.append(_driver.CUjit_option.CU_JIT_TARGET) 175

470 if self.max_register_count is not None: 27 5 . / : ; = ? @ NbObMbJbHbEb

471 formatted_options.append(self.max_register_count) 15

472 option_keys.append(_driver.CUjit_option.CU_JIT_MAX_REGISTERS) 15

473 if self.time is not None: 27 5 . / : ; = ? @ NbObMbJbHbEb

474 raise ValueError("time option is not supported by the driver API") 2Ob

475 if self.verbose: 27 5 . / : ; = ? @ NbMbJbHbEb

476 formatted_options.append(1) 15

477 option_keys.append(_driver.CUjit_option.CU_JIT_LOG_VERBOSE) 15

478 if self.link_time_optimization: 27 5 . / : ; = ? @ NbMbJbHbEb

479 formatted_options.append(1) 15

480 option_keys.append(_driver.CUjit_option.CU_JIT_LTO) 15

481 if self.incremental: 27 5 . / : ; = ? @ NbMbJbHbEb

482 raise ValueError("incremental option is not supported by the driver API") 2Nb

483 if self.ptx: 27 5 . / : ; = ? @ MbJbHbEb

484 raise ValueError("ptx option is not supported by the driver API") 2Mb

485 if self.optimization_level is not None: 27 5 . / : ; = ? @ JbHbEb

486 formatted_options.append(self.optimization_level) 15

487 option_keys.append(_driver.CUjit_option.CU_JIT_OPTIMIZATION_LEVEL) 15

488 if self.debug: 27 5 . / : ; = ? @ JbHbEb

489 formatted_options.append(1) 15

490 option_keys.append(_driver.CUjit_option.CU_JIT_GENERATE_DEBUG_INFO) 15

491 if self.lineinfo: 27 5 . / : ; = ? @ JbHbEb

492 formatted_options.append(1) 15

493 option_keys.append(_driver.CUjit_option.CU_JIT_GENERATE_LINE_INFO) 15

494 if self.ftz is not None: 27 5 . / : ; = ? @ JbHbEb

495 warn("ftz option is deprecated in the driver API", DeprecationWarning, stacklevel=3) 1.

496 if self.prec_div is not None: 27 5 . / : ; = ? @ JbHbEb

497 warn("prec_div option is deprecated in the driver API", DeprecationWarning, stacklevel=3) 1/

498 if self.prec_sqrt is not None: 27 5 . / : ; = ? @ JbHbEb

499 warn("prec_sqrt option is deprecated in the driver API", DeprecationWarning, stacklevel=3) 1:

500 if self.fma is not None: 27 5 . / : ; = ? @ JbHbEb

501 warn("fma options is deprecated in the driver API", DeprecationWarning, stacklevel=3) 1;

502 if self.kernels_used is not None: 27 5 . / : ; = ? @ JbHbEb

503 warn("kernels_used is deprecated in the driver API", DeprecationWarning, stacklevel=3) 1=

504 if self.variables_used is not None: 27 5 . / : ; = ? @ JbHbEb

505 warn("variables_used is deprecated in the driver API", DeprecationWarning, stacklevel=3) 1?

506 if self.optimize_unused_variables is not None: 27 5 . / : ; = ? @ JbHbEb

507 warn("optimize_unused_variables is deprecated in the driver API", DeprecationWarning, stacklevel=3) 1@

508 if self.ptxas_options is not None: 27 5 . / : ; = ? @ JbHbEb

509 raise ValueError("ptxas_options option is not supported by the driver API") 2Jb

510 if self.split_compile is not None: 27 5 . / : ; = ? @ HbEb

511 raise ValueError("split_compile option is not supported by the driver API") 2Hb

512 if self.split_compile_extended is not None: 27 5 . / : ; = ? @ Eb

513 raise ValueError("split_compile_extended option is not supported by the driver API") 2Eb

514 if self.no_cache is True: 175./:;=?@

515 formatted_options.append(_driver.CUjit_cacheMode.CU_JIT_CACHE_OPTION_NONE) 15

516 option_keys.append(_driver.CUjit_option.CU_JIT_CACHE_MODE) 15

517  

518 return formatted_options, option_keys 175./:;=?@

519  

520 def as_bytes(self, backend: str = "nvjitlink") -> list[bytes]: 

521 """Convert linker options to bytes format for the nvjitlink backend. 

522  

523 Parameters 

524 ---------- 

525 backend : str, optional 

526 The linker backend. Only "nvjitlink" is supported. Default is "nvjitlink". 

527  

528 Returns 

529 ------- 

530 list[bytes] 

531 List of option strings encoded as bytes. 

532  

533 Raises 

534 ------ 

535 ValueError 

536 If an unsupported backend is specified. 

537 RuntimeError 

538 If nvJitLink backend is not available. 

539 """ 

540 backend = backend.lower() 2WbYbZb8 qbrb[ sbtbubvb] ^ _ ` { | } ~ 9 ! % ' wbxbybzbabbbcbdbebfbgbhb# $ ( ) AbBbCbDbibjbkblbmbnbobpb* + , -

541 if backend != "nvjitlink": 2WbYbZb8 qbrb[ sbtbubvb] ^ _ ` { | } ~ 9 ! % ' wbxbybzbabbbcbdbebfbgbhb# $ ( ) AbBbCbDbibjbkblbmbnbobpb* + , -

542 raise ValueError(f"as_bytes() only supports 'nvjitlink' backend, got '{backend}'") 2YbZb

543 if not _use_nvjitlink_backend: 2Wb8 qbrb[ sbtbubvb] ^ _ ` { | } ~ 9 ! % ' wbxbybzbabbbcbdbebfbgbhb# $ ( ) AbBbCbDbibjbkblbmbnbobpb* + , -

544 raise RuntimeError("nvJitLink backend is not available") 2Wb

545 return self._prepare_nvjitlink_options(as_bytes=True) 28 qbrb[ sbtbubvb] ^ _ ` { | } ~ 9 ! % ' wbxbybzbabbbcbdbebfbgbhb# $ ( ) AbBbCbDbibjbkblbmbnbobpb* + , -

546  

547  

548# ============================================================================= 

549# Private implementation: cdef inline helpers 

550# ============================================================================= 

551  

552cdef inline int Linker_init(Linker self, tuple object_codes, object options) except -1: 

553 """Initialize a Linker instance.""" 

554 if len(object_codes) == 0: 2n b q Tb0 e a 1bX z 4 V A L M B N C O u v o P Q R S T U D w E F x G W 6 H 2 I p y f Y Z 1 J K 3 r s t g c h i j k l d m

555 raise ValueError("At least one ObjectCode object must be provided") 21b

556  

557 cdef cynvjitlink.nvJitLinkHandle c_raw_nvjitlink 

558 cdef cydriver.CUlinkState c_raw_culink 

559 cdef Py_ssize_t c_num_opts, i 

560 cdef vector[const_char_ptr] c_str_opts 

561 cdef cydriver.CUjit_option* c_drv_jit_keys_ptr 

562 cdef void** c_drv_jit_values_ptr 

563  

564 self._options = options = check_or_create_options(LinkerOptions, options, "Linker options") 2n b q Tb0 e a X z 4 V A L M B N C O u v o P Q R S T U D w E F x G W 6 H 2 I p y f Y Z 1 J K 3 r s t g c h i j k l d m

565 self._has_ptx_or_cubin_input = False 2n b q Tb0 e a X z 4 V A L M B N C O u v o P Q R S T U D w E F x G W 6 H 2 I p y f Y Z 1 J K 3 r s t g c h i j k l d m

566 if options.incremental and options.ptx: 2n b q Tb0 e a X z 4 V A L M B N C O u v o P Q R S T U D w E F x G W 6 H 2 I p y f Y Z 1 J K 3 r s t g c h i j k l d m

567 raise ValueError("incremental and ptx output options cannot be used together") 2Tb

568  

569 if _use_nvjitlink_backend: 1nbq0eaXz4VALMBNCOuvoPQRSTUDwEFxGW6H2IpyfYZ1JK3rstgchijkldm

570 if options.incremental: 1nbq0eaXz4VALMBNCOuvoPQRSTUDwEFxGW6H2IpyfYZ1JK3rstgchijkldm

571 _require_nvjitlink_version((13, 2), "incremental linking") 1q0eaYZ

572 self._use_nvjitlink = True 1nbq0eaXz4VALMBNCOuvoPQRSTUDwEFxGW6H2IpyfYZ1JK3rstgchijkldm

573 options_bytes = options._prepare_nvjitlink_options(as_bytes=True) 1nbq0eaXz4VALMBNCOuvoPQRSTUDwEFxGW6H2IpyfYZ1JK3rstgchijkldm

574 c_num_opts = len(options_bytes) 1nbq0eaXz4VALMBNCOuvoPQRSTUDwEFxGW6H2IpyfYZ1JK3rstgchijkldm

575 c_str_opts.resize(c_num_opts) 1nbq0eaXz4VALMBNCOuvoPQRSTUDwEFxGW6H2IpyfYZ1JK3rstgchijkldm

576 for i in range(c_num_opts): 1nbq0eaXz4VALMBNCOuvoPQRSTUDwEFxGW6H2IpyfYZ1JK3rstgchijkldm

577 c_str_opts[i] = <const char*>(<bytes>options_bytes[i]) 1nbq0eaXz4VALMBNCOuvoPQRSTUDwEFxGW6H2IpyfYZ1JK3rstgchijkldm

578 with nogil: 1nbq0eaXz4VALMBNCOuvoPQRSTUDwEFxGW6H2IpyfYZ1JK3rstgchijkldm

579 HANDLE_RETURN_NVJITLINK(NULL, cynvjitlink.nvJitLinkCreate( 1nbq0eaXz4VALMBNCOuvoPQRSTUDwEFxGW6H2IpyfYZ1JK3rstgchijkldm

580 &c_raw_nvjitlink, <uint32_t>c_num_opts, c_str_opts.data())) 

581 self._nvjitlink_handle = create_nvjitlink_handle(c_raw_nvjitlink) 1nbq0eaXz4VALMBNCOuvoPQRSTUDwEFxGWH2IpyfYZ1JK3rstgchijkldm

582 else: 

583 self._use_nvjitlink = False 

584 formatted_options, option_keys = options._prepare_driver_options() 

585 # Keep the formatted_options list alive: it contains bytearrays that 

586 # the driver writes into via raw pointers during linking operations. 

587 self._drv_log_bufs = formatted_options 

588 c_num_opts = len(option_keys) 

589 self._drv_jit_keys.resize(c_num_opts) 

590 self._drv_jit_values.resize(c_num_opts) 

591 for i in range(c_num_opts): 

592 self._drv_jit_keys[i] = <cydriver.CUjit_option><int>option_keys[i] 

593 val = formatted_options[i] 

594 if isinstance(val, bytearray): 

595 self._drv_jit_values[i] = <void*>PyByteArray_AS_STRING(val) 

596 else: 

597 self._drv_jit_values[i] = <void*><intptr_t>int(val) 

598 c_drv_jit_keys_ptr = self._drv_jit_keys.data() 

599 c_drv_jit_values_ptr = self._drv_jit_values.data() 

600 try: 

601 with nogil: 

602 HANDLE_RETURN(cydriver.cuLinkCreate( 

603 <unsigned int>c_num_opts, 

604 c_drv_jit_keys_ptr, 

605 c_drv_jit_values_ptr, 

606 &c_raw_culink)) 

607 except CUDAError as e: 

608 Linker_annotate_error_log(self, e) 

609 raise 

610 self._culink_handle = create_culink_handle(c_raw_culink) 

611  

612 for code in object_codes: 1nbq0eaXz4VALMBNCOuvoPQRSTUDwEFxGWH2IpyfYZ1JK3rstgchijkldm

613 assert_type(code, ObjectCode) 1nbq0eaXz4VALMBNCOuvoPQRSTUDwEFxGWH2IpyfYZ1JK3rstgchijkldm

614 Linker_add_code_object(self, code) 1nbq0eaXz4VALMBNCOuvoPQRSTUDwEFxGWH2IpyfYZ1JK3rstgchijkldm

615 return 0 1nbq0eaXz4VALMBNCOuvoPQRSTUDwEFxGWH2IpyfYZ1JK3rstgchijkldm

616  

617  

618cdef inline void Linker_add_code_object(Linker self, object object_code) except *: 

619 """Add a single ObjectCode to the linker.""" 

620 data = object_code.code 1nbq0eaXz4VALMBNCOuvoPQRSTUDwEFxGWH2IpyfYZ1JK3rstgchijkldm

621 cdef cynvjitlink.nvJitLinkHandle c_nvjitlink_h 

622 cdef cydriver.CUlinkState c_culink_state 

623 cdef cynvjitlink.nvJitLinkInputType c_nv_input_type 

624 cdef cydriver.CUjitInputType c_drv_input_type 

625 cdef const char* c_data_ptr 

626 cdef size_t c_data_size 

627 cdef const char* c_file_ptr 

628  

629 name_bytes = f"{object_code.name}".encode() 1nbq0eaXz4VALMBNCOuvoPQRSTUDwEFxGWH2IpyfYZ1JK3rstgchijkldm

630 cdef const char* c_name_ptr = <const char*>name_bytes 1nbq0eaXz4VALMBNCOuvoPQRSTUDwEFxGWH2IpyfYZ1JK3rstgchijkldm

631  

632 input_types = _nvjitlink_input_types if self._use_nvjitlink else _driver_input_types 1nbq0eaXz4VALMBNCOuvoPQRSTUDwEFxGWH2IpyfYZ1JK3rstgchijkldm

633 py_input_type = input_types.get(object_code.code_type) 1nbq0eaXz4VALMBNCOuvoPQRSTUDwEFxGWH2IpyfYZ1JK3rstgchijkldm

634 if py_input_type is None: 1nbq0eaXz4VALMBNCOuvoPQRSTUDwEFxGWH2IpyfYZ1JK3rstgchijkldm

635 raise ValueError(f"Unknown code_type associated with ObjectCode: {object_code.code_type}") 

636  

637 if self._use_nvjitlink: 1nbq0eaXz4VALMBNCOuvoPQRSTUDwEFxGWH2IpyfYZ1JK3rstgchijkldm

638 c_nvjitlink_h = as_cu(self._nvjitlink_handle) 1nbq0eaXz4VALMBNCOuvoPQRSTUDwEFxGWH2IpyfYZ1JK3rstgchijkldm

639 c_nv_input_type = <cynvjitlink.nvJitLinkInputType><int>py_input_type 1nbq0eaXz4VALMBNCOuvoPQRSTUDwEFxGWH2IpyfYZ1JK3rstgchijkldm

640 if isinstance(data, bytes): 1nbq0eaXz4VALMBNCOuvoPQRSTUDwEFxGWH2IpyfYZ1JK3rstgchijkldm

641 c_data_ptr = <const char*>(<bytes>data) 1nbq0eaXz4VALMBNCOuvoPQRSTUDwEFxGWH2IpyfYZ1JK3rstgchijkldm

642 c_data_size = len(data) 1nbq0eaXz4VALMBNCOuvoPQRSTUDwEFxGWH2IpyfYZ1JK3rstgchijkldm

643 with nogil: 1nbq0eaXz4VALMBNCOuvoPQRSTUDwEFxGWH2IpyfYZ1JK3rstgchijkldm

644 HANDLE_RETURN_NVJITLINK(c_nvjitlink_h, cynvjitlink.nvJitLinkAddData( 1nbq0eaXz4VALMBNCOuvoPQRSTUDwEFxGWH2IpyfYZ1JK3rstgchijkldm

645 c_nvjitlink_h, c_nv_input_type, <const void*>c_data_ptr, c_data_size, c_name_ptr)) 

646 elif isinstance(data, str): 

647 file_bytes = data.encode() 

648 c_file_ptr = <const char*>file_bytes 

649 with nogil: 

650 HANDLE_RETURN_NVJITLINK(c_nvjitlink_h, cynvjitlink.nvJitLinkAddFile( 

651 c_nvjitlink_h, c_nv_input_type, c_file_ptr)) 

652 else: 

653 raise TypeError(f"Expected bytes or str, but got {type(data).__name__}") 

654 else: 

655 c_culink_state = as_cu(self._culink_handle) 

656 c_drv_input_type = <cydriver.CUjitInputType><int>py_input_type 

657 try: 

658 if isinstance(data, bytes): 

659 c_data_ptr = <const char*>(<bytes>data) 

660 c_data_size = len(data) 

661 with nogil: 

662 HANDLE_RETURN(cydriver.cuLinkAddData( 

663 c_culink_state, c_drv_input_type, <void*>c_data_ptr, c_data_size, c_name_ptr, 

664 0, NULL, NULL)) 

665 elif isinstance(data, str): 

666 file_bytes = data.encode() 

667 c_file_ptr = <const char*>file_bytes 

668 with nogil: 

669 HANDLE_RETURN(cydriver.cuLinkAddFile( 

670 c_culink_state, c_drv_input_type, c_file_ptr, 0, NULL, NULL)) 

671 else: 

672 raise TypeError(f"Expected bytes or str, but got {type(data).__name__}") 

673 except CUDAError as e: 

674 Linker_annotate_error_log(self, e) 

675 raise 

676  

677 if object_code.code_type in ("ptx", "cubin"): 1nbq0eaXz4VALMBNCOuvoPQRSTUDwEFxGWH2IpyfYZ1JK3rstgchijkldm

678 self._has_ptx_or_cubin_input = True 1nq0eXz4VALMBNCOuvoPQRSTUDwEFxGWH2IyYZ1JK3rstgchijkldm

679  

680  

681cdef inline object Linker_link(Linker self, str target_type): 

682 """Complete linking and return the result as ObjectCode.""" 

683 if target_type not in ("cubin", "ptx", "ltoir"): 1nbq0eaXzVALMBNCOuvoPQRSTUDwEFxGWH2IpyfYZ1JKrstgchijkldm

684 raise ValueError(f"Unsupported target type: {target_type}") 12

685 if self._options.incremental and target_type == "ptx": 1nbq0eaXzVALMBNCOuvoPQRSTUDwEFxGWHIpyfYZ1JKrstgchijkldm

686 raise ValueError("PTX output is not supported for incremental linking") 10

687 if target_type == "ltoir": 1nbqeaXzVALMBNCOuvoPQRSTUDwEFxGWHIpyfYZ1JKrstgchijkldm

688 if not self._use_nvjitlink: 1baYZ1

689 raise ValueError("LTOIR output is not supported by the driver API") 

690 if not self._options.link_time_optimization: 1baYZ1

691 raise ValueError("LTOIR output requires link_time_optimization=True") 11

692 if self._has_ptx_or_cubin_input: 1baYZ

693 raise ValueError( 1YZ

694 'LTOIR output is not supported with "ptx" or "cubin" inputs; ' 

695 "they carry no LTOIR and would be omitted from the output" 

696 ) 

697 _require_nvjitlink_version((13, 3), "LTOIR output") 1ba

698  

699 cdef cynvjitlink.nvJitLinkHandle c_nvjitlink_h 

700 cdef cydriver.CUlinkState c_culink_state 

701 cdef size_t c_output_size = 0 1nbqeaXzVALMBNCOuvoPQRSTUDwEFxGWHIpyfJKrstgchijkldm

702 cdef char* c_code_ptr 

703 cdef void* c_cubin_out = NULL 1nbqeaXzVALMBNCOuvoPQRSTUDwEFxGWHIpyfJKrstgchijkldm

704  

705 if self._use_nvjitlink: 1nbqeaXzVALMBNCOuvoPQRSTUDwEFxGWHIpyfJKrstgchijkldm

706 c_nvjitlink_h = as_cu(self._nvjitlink_handle) 1nbqeaXzVALMBNCOuvoPQRSTUDwEFxGWHIpyfJKrstgchijkldm

707 with nogil: 1nbqeaXzVALMBNCOuvoPQRSTUDwEFxGWHIpyfJKrstgchijkldm

708 HANDLE_RETURN_NVJITLINK(c_nvjitlink_h, cynvjitlink.nvJitLinkComplete(c_nvjitlink_h)) 1nbqeaXzVALMBNCOuvoPQRSTUDwEFxGWHIpyfJKrstgchijkldm

709 if target_type == "cubin": 1nbqeazVALMBNCOuvoPQRSTUDwEFxGWHIpyfJKrstgchijkldm

710 HANDLE_RETURN_NVJITLINK(c_nvjitlink_h, 1nbqeazVALMBNCOuvoPQRSTUDwEFxGWHIyfJKrstgchijkldm

711 cynvjitlink.nvJitLinkGetLinkedCubinSize(c_nvjitlink_h, &c_output_size)) 1nbqeazVALMBNCOuvoPQRSTUDwEFxGWHIyfJKrstgchijkldm

712 code = bytearray(c_output_size) 1nbqeazVALMBNCOuvoPQRSTUDwEFxGWHIyfJKrstgchijkldm

713 c_code_ptr = <char*>(<bytearray>code) 1nbqeazVALMBNCOuvoPQRSTUDwEFxGWHIyfJKrstgchijkldm

714 with nogil: 1nbqeazVALMBNCOuvoPQRSTUDwEFxGWHIyfJKrstgchijkldm

715 HANDLE_RETURN_NVJITLINK(c_nvjitlink_h, 1nbqeazVALMBNCOuvoPQRSTUDwEFxGWHIyfJKrstgchijkldm

716 cynvjitlink.nvJitLinkGetLinkedCubin(c_nvjitlink_h, c_code_ptr)) 1nbqeazVALMBNCOuvoPQRSTUDwEFxGWHIyfJKrstgchijkldm

717 elif target_type == "ptx": 1bap

718 HANDLE_RETURN_NVJITLINK(c_nvjitlink_h, 1p

719 cynvjitlink.nvJitLinkGetLinkedPtxSize(c_nvjitlink_h, &c_output_size)) 1p

720 code = bytearray(c_output_size) 1p

721 c_code_ptr = <char*>(<bytearray>code) 1p

722 with nogil: 1p

723 HANDLE_RETURN_NVJITLINK(c_nvjitlink_h, 1p

724 cynvjitlink.nvJitLinkGetLinkedPtx(c_nvjitlink_h, c_code_ptr)) 1p

725 else: 

726 HANDLE_RETURN_NVJITLINK(c_nvjitlink_h, 1ba

727 cynvjitlink.nvJitLinkGetLinkedLTOIRSize(c_nvjitlink_h, &c_output_size)) 1ba

728 code = bytearray(c_output_size) 1ba

729 c_code_ptr = <char*>(<bytearray>code) 1ba

730 with nogil: 1ba

731 HANDLE_RETURN_NVJITLINK(c_nvjitlink_h, 1ba

732 cynvjitlink.nvJitLinkGetLinkedLTOIR(c_nvjitlink_h, c_code_ptr)) 1ba

733 else: 

734 c_culink_state = as_cu(self._culink_handle) 

735 try: 

736 with nogil: 

737 HANDLE_RETURN(cydriver.cuLinkComplete(c_culink_state, &c_cubin_out, &c_output_size)) 

738 except CUDAError as e: 

739 Linker_annotate_error_log(self, e) 

740 raise 

741 code = (<char*>c_cubin_out)[:c_output_size] 

742  

743 # Linking is complete; cache the decoded logs. cuLinkDestroy may still 

744 # dereference the raw log-buffer pointers, so retain them until close(). 

745 self._info_log = self.get_info_log() 1nbqeazVALMBNCOuvoPQRSTUDwEFxGWHIpyfJKrstgchijkldm

746 self._error_log = self.get_error_log() 1nbqeazVALMBNCOuvoPQRSTUDwEFxGWHIpyfJKrstgchijkldm

747  

748 return ObjectCode._init(bytes(code), target_type, name=self._options.name) 1nbqeazVALMBNCOuvoPQRSTUDwEFxGWHIpyfJKrstgchijkldm

749  

750  

751cdef inline void Linker_annotate_error_log(Linker self, object e): 

752 """Annotate a CUDAError with the driver linker error log.""" 

753 error_log = self.get_error_log() 

754 if error_log: 

755 e.args = (e.args[0] + f"\nLinker error log: {error_log}", *e.args[1:]) 

756  

757  

758# ============================================================================= 

759# Private implementation: module-level state and initialization 

760# ============================================================================= 

761  

762# TODO: revisit this treatment for py313t builds 

763_driver = None # populated if nvJitLink cannot be used 

764_nvjitlink_version = None 

765_inited = False 

766_use_nvjitlink_backend = None # set by _decide_nvjitlink_or_driver() 

767  

768# Input type mappings populated by _lazy_init() with C-level enum ints. 

769_nvjitlink_input_types = None 

770_driver_input_types = None 

771  

772  

773def _require_nvjitlink_version(minimum_version: tuple[int, int], feature: str) -> None: 

774 """Check that the cached nvJitLink runtime meets a feature's requirement.""" 

775 if _nvjitlink_version < minimum_version: 2b q 0 e a Y Z `b0b

776 required = ".".join(str(component) for component in minimum_version) 20b

777 detected = ".".join(str(component) for component in _nvjitlink_version) 20b

778 raise RuntimeError(f"{feature} requires nvJitLink {required} or newer; found {detected}") 20b

779  

780  

781def _nvjitlink_has_version_symbol(nvjitlink) -> bool: 

782 # This condition is equivalent to testing for version >= 12.3 

783 return bool(nvjitlink._inspect_function_pointer("__nvJitLinkVersion")) 

784  

785  

786# Note: this function is reused in the tests 

787def _decide_nvjitlink_or_driver() -> bool: 

788 """Return True if falling back to the cuLink* driver APIs.""" 

789 global _driver, _nvjitlink_version, _use_nvjitlink_backend 

790 if _use_nvjitlink_backend is not None: 2LbUbQbPb2b3bV A L M B N C O u v o P Q R S T U D w E F x G W RbVbSbXb3 r s t g c h i j k l d m 4b5b6b7b8b9b!b#b$b%b'b(b)b*b+b,b-b.b/b:b;b=b?b@b[b]b^b

791 return not _use_nvjitlink_backend 2LbUb2b3bV A L M B N C O u v o P Q R S T U D w E F x G W 3 r s t g c h i j k l d m 4b5b6b7b8b9b!b#b$b%b'b(b)b*b+b,b-b.b/b:b;b=b?b@b[b]b^b

792  

793 warn_txt_common = ( 

794 "the driver APIs will be used instead, which do not support" 2LbUbQbPbRbVbSbXb

795 " minor version compatibility or linking LTO IRs." 

796 " For best results, consider upgrading to a recent version of" 

797 ) 

798  

799 # Every cuda-bindings that cuda.core accepts provides cuda.bindings.nvjitlink. 

800 # Only the nvJitLink library itself can be missing or too old. 

801 from cuda.bindings._internal import nvjitlink 2LbUbQbPbRbVbSbXb

802  

803 try: 2LbUbQbPbRbVbSbXb

804 has_version_symbol = _nvjitlink_has_version_symbol(nvjitlink) 2LbUbQbPbRbVbSbXb

805 except DynamicLibNotFoundError: 2QbVb

806 warn_txt = ( 

807 f"cuda.bindings.nvjitlink is not available, therefore {warn_txt_common} cuda-bindings." 2QbVb

808 ) 

809 else: 

810 if has_version_symbol: 2LbUbPbRbSbXb

811 _nvjitlink_version = _nvjitlink_bindings.version() 2LbUbXb

812 _use_nvjitlink_backend = True 2LbUbXb

813 return False # Use nvjitlink 2LbUbXb

814 warn_txt = ( 

815 f"{'nvJitLink*.dll' if sys.platform == 'win32' else 'libnvJitLink.so*'} is too old (<12.3)." 2PbRbSb

816 f" Therefore cuda.bindings.nvjitlink is not usable and {warn_txt_common} nvJitLink." 2PbRbSb

817 ) 

818  

819 warn(warn_txt, stacklevel=2, category=RuntimeWarning) 2QbPbRbVbSb

820 _driver = driver 2QbPbRbVbSb

821 _use_nvjitlink_backend = False 2QbPbRbVbSb

822 return True 2QbPbRbVbSb

823  

824  

825def _lazy_init() -> None: 

826 global _inited, _nvjitlink_input_types, _driver_input_types 

827 if _inited: 2LbWbn b q Tb0 e a X z 4 6 H 2 I p y f YbZb8 qbrb[ sbtbubvb] ^ _ ` { | } ~ 9 ! % ' wbxbybzbabbbcbdbebfbgbhb# $ ( ) AbBbCbDbibjbkblbmbnbobpb* + , - IbY Z 1 7 KbFbGb5 . / : ; = ? @ NbObMbJbHbEbJ K 3 r s t g c h i j k l d m

828 return 2LbWbn b q Tb0 e a X z 4 6 H 2 I p y f YbZb8 qbrb[ sbtbubvb] ^ _ ` { | } ~ 9 ! % ' wbxbybzbabbbcbdbebfbgbhb# $ ( ) AbBbCbDbibjbkblbmbnbobpb* + , - IbY Z 1 7 KbFbGb5 . / : ; = ? @ NbObMbJbHbEbJ K 3 r s t g c h i j k l d m

829  

830 _decide_nvjitlink_or_driver() 

831 if _use_nvjitlink_backend: 

832 _nvjitlink_input_types = { 

833 "ptx": <int>cynvjitlink.NVJITLINK_INPUT_PTX, 

834 "cubin": <int>cynvjitlink.NVJITLINK_INPUT_CUBIN, 

835 "fatbin": <int>cynvjitlink.NVJITLINK_INPUT_FATBIN, 

836 "ltoir": <int>cynvjitlink.NVJITLINK_INPUT_LTOIR, 

837 "object": <int>cynvjitlink.NVJITLINK_INPUT_OBJECT, 

838 "library": <int>cynvjitlink.NVJITLINK_INPUT_LIBRARY, 

839 } 

840 else: 

841 _driver_input_types = { 

842 "ptx": <int>cydriver.CU_JIT_INPUT_PTX, 

843 "cubin": <int>cydriver.CU_JIT_INPUT_CUBIN, 

844 "fatbin": <int>cydriver.CU_JIT_INPUT_FATBINARY, 

845 "object": <int>cydriver.CU_JIT_INPUT_OBJECT, 

846 "library": <int>cydriver.CU_JIT_INPUT_LIBRARY, 

847 } 

848 _inited = True