Sarek_cuda.Cuda_nvrtcval nvrtc_program : nvrtc_program Ctypes.structure Ctypes.typval nvrtc_program_ptr : nvrtc_program Ctypes.structure Ctypes.ptr Ctypes.typtype nvrtc_result = | NVRTC_SUCCESS| NVRTC_ERROR_OUT_OF_MEMORY| NVRTC_ERROR_PROGRAM_CREATION_FAILURE| NVRTC_ERROR_INVALID_INPUT| NVRTC_ERROR_INVALID_PROGRAM| NVRTC_ERROR_INVALID_OPTION| NVRTC_ERROR_COMPILATION| NVRTC_ERROR_BUILTIN_OPERATION_FAILURE| NVRTC_ERROR_NO_NAME_EXPRESSIONS_AFTER_COMPILATION| NVRTC_ERROR_NO_LOWERED_NAMES_BEFORE_COMPILATION| NVRTC_ERROR_NAME_EXPRESSION_NOT_VALID| NVRTC_ERROR_INTERNAL_ERROR| NVRTC_ERROR_UNKNOWN of intNVRTC result codes
val nvrtc_result_of_int : int -> nvrtc_resultval int_of_nvrtc_result : nvrtc_result -> intval nvrtc_result : nvrtc_result Ctypes.typval string_of_nvrtc_result : nvrtc_result -> stringLoad NVRTC library dynamically (lazy). Prefer unversioned to get system default that matches driver.
Create a lazy foreign binding to NVRTC
val nvrtcVersion_lazy :
(int Ctypes_static.ptr -> int Ctypes_static.ptr -> nvrtc_result) lazy_tval nvrtcVersion :
int Ctypes_static.ptr ->
int Ctypes_static.ptr ->
nvrtc_resultval nvrtcCreateProgram_lazy :
(nvrtc_program Ctypes.structure Ctypes.ptr Ctypes_static.ptr ->
string ->
string option ->
int ->
string option Ctypes_static.ptr ->
string option Ctypes_static.ptr ->
nvrtc_result)
lazy_tval nvrtcCreateProgram :
nvrtc_program Ctypes.structure Ctypes.ptr Ctypes_static.ptr ->
string ->
string option ->
int ->
string option Ctypes_static.ptr ->
string option Ctypes_static.ptr ->
nvrtc_resultval nvrtcDestroyProgram_lazy :
(nvrtc_program Ctypes.structure Ctypes.ptr Ctypes_static.ptr ->
nvrtc_result)
lazy_tval nvrtcDestroyProgram :
nvrtc_program Ctypes.structure Ctypes.ptr Ctypes_static.ptr ->
nvrtc_resultval nvrtcCompileProgram_lazy :
(nvrtc_program Ctypes.structure Ctypes.ptr ->
int ->
string Ctypes_static.ptr ->
nvrtc_result)
lazy_tval nvrtcCompileProgram :
nvrtc_program Ctypes.structure Ctypes.ptr ->
int ->
string Ctypes_static.ptr ->
nvrtc_resultval nvrtcGetPTXSize_lazy :
(nvrtc_program Ctypes.structure Ctypes.ptr ->
Unsigned.size_t Ctypes_static.ptr ->
nvrtc_result)
lazy_tval nvrtcGetPTXSize :
nvrtc_program Ctypes.structure Ctypes.ptr ->
Unsigned.size_t Ctypes_static.ptr ->
nvrtc_resultval nvrtcGetPTX_lazy :
(nvrtc_program Ctypes.structure Ctypes.ptr ->
char Ctypes_static.ptr ->
nvrtc_result)
lazy_tval nvrtcGetPTX :
nvrtc_program Ctypes.structure Ctypes.ptr ->
char Ctypes_static.ptr ->
nvrtc_resultval nvrtcGetCUBINSize_lazy :
(nvrtc_program Ctypes.structure Ctypes.ptr ->
Unsigned.size_t Ctypes_static.ptr ->
nvrtc_result)
option
lazy_tval nvrtcGetCUBINSize :
nvrtc_program Ctypes.structure Ctypes.ptr ->
Unsigned.size_t Ctypes_static.ptr ->
nvrtc_resultval nvrtcGetCUBIN_lazy :
(nvrtc_program Ctypes.structure Ctypes.ptr ->
char Ctypes_static.ptr ->
nvrtc_result)
option
lazy_tval nvrtcGetCUBIN :
nvrtc_program Ctypes.structure Ctypes.ptr ->
char Ctypes_static.ptr ->
nvrtc_resultval nvrtcGetProgramLogSize_lazy :
(nvrtc_program Ctypes.structure Ctypes.ptr ->
Unsigned.size_t Ctypes_static.ptr ->
nvrtc_result)
lazy_tval nvrtcGetProgramLogSize :
nvrtc_program Ctypes.structure Ctypes.ptr ->
Unsigned.size_t Ctypes_static.ptr ->
nvrtc_resultval nvrtcGetProgramLog_lazy :
(nvrtc_program Ctypes.structure Ctypes.ptr ->
char Ctypes_static.ptr ->
nvrtc_result)
lazy_tval nvrtcGetProgramLog :
nvrtc_program Ctypes.structure Ctypes.ptr ->
char Ctypes_static.ptr ->
nvrtc_resultval nvrtcAddNameExpression_lazy :
(nvrtc_program Ctypes.structure Ctypes.ptr -> string -> nvrtc_result) lazy_tval nvrtcAddNameExpression :
nvrtc_program Ctypes.structure Ctypes.ptr ->
string ->
nvrtc_resultval nvrtcGetLoweredName_lazy :
(nvrtc_program Ctypes.structure Ctypes.ptr ->
string ->
string Ctypes_static.ptr ->
nvrtc_result)
lazy_tval nvrtcGetLoweredName :
nvrtc_program Ctypes.structure Ctypes.ptr ->
string ->
string Ctypes_static.ptr ->
nvrtc_resultexception Nvrtc_error of nvrtc_result * stringException for NVRTC errors
val check : string -> nvrtc_result -> unitCheck result and raise if error
CUDA header search path
NVRTC has NO default include path. It is a library, not a driver, so it does not inherit the built-in -I that nvcc adds, and __half is not an nvrtc builtin. A generated kernel that says #include <cuda_fp16.h> — which is exactly what the f16 codegen emits, see Sarek_codegen.Sarek_ir_cuda.cuda_fp16_include — therefore fails with NVRTC_ERROR_COMPILATION and
could not open source file "cuda_fp16.h" (no directories in search list)
unless the toolkit's include directory is passed explicitly. Verified against libnvrtc 13.3: byte-identical source compiles to PTX containing cvt.rn.f16.f32 with the flag and fails without it.
Discovery order (every surviving candidate is passed, so a partial toolkit layout still resolves):
SAREK_CUDA_INCLUDE — explicit ':'-separated override, kept if the directory exists;CUDA_PATH / CUDA_HOME / CUDA_ROOT derived include and targets/<triple>/include;Derived and conventional candidates must additionally CONTAIN cuda_fp16.h. That marker is what keeps the discovery honest: a stale CUDA_PATH or a bare /usr/include never becomes an -I that could shadow a real header. On a machine with no CUDA headers the list is empty and the option array is byte-identical to before, so non-CUDA hosts are unaffected.
Passed unconditionally rather than gated on the f16 detector: this module never sees the IR, an unused include directory cannot change a kernel that includes nothing, and gating here would leave any future header-using codegen broken in the same way.
Existing CUDA include directories, most-specific first, de-duplicated.
The --include-path= flags derived from cuda_include_paths.
Floating-point conformance guard
Raised when an nvrtc option would change binary32 semantics in a way the interpreter — Sarek's cross-backend oracle — cannot follow. Carries the offending option and why it is refused.
The floating-point option classes this path refuses, and why.
The rule these encode: Sarek's DSL semantics are IEEE-754 binary32 with every operation rounded as written, and the interpreter implements exactly that. An option that FLUSHES SUBNORMALS or DOWNGRADES a division/square root to an approximate form makes the device disagree with the interpreter on inputs the test suite already uses, and — unlike HIP's contraction case, where appending -ffp-contract=off last neutralises the caller — there is no later flag that undoes it. So these are rejected rather than warned about.
-use_fast_math implies --ftz=true --prec-div=false --prec-sqrt=false --fmad=true (CUDA nvrtc documentation, dependencies/Cuda/nvrtc.h).-ftz=true flushes binary32 subnormals to zero. MEASURED, host-side on CUDA 13.3 (nvcc/ptxas V13.3.73, no NVIDIA device): compiling the generated f16_midround kernel for sm_90 with -use_fast_math or -ftz=true turns FMUL/FADD into FMUL.FTZ/FADD.FTZ. 1e-5 is already lane 5 of the test_hip_f16 input array, so this is reachable from the existing test data, not a hypothetical.--prec-div=false / --prec-sqrt=false select approximate division and square root. Sarek_df64 already spends its whole error budget on the correctly-rounded forms — the PTX emitter switched div.approx.f32 to div.rn.f32 for exactly this reason (audit finding M2).--fmad=true is NOT refused: it is nvrtc's default, so refusing it would refuse the status quo. Contraction is instead defeated by construction where it matters (see Sarek_df64's contraction barrier). It warns, so a caller who sets it deliberately is told the guarantee it is trading away.
NVRTC ACCEPTS AN OPTION AND ITS VALUE AS TWO SEPARATE ARRAY ELEMENTS. An earlier version of this guard matched ["--ftz=true"] and walked straight past ["--ftz"; "true"] — executed against libnvrtc 13.3 through these bindings, the separated form compiled and the PTX carried .ftz on the f32 arithmetic, with no exception and no warning. So the scan below is written around the OPTION, not its spelling: a value-taking name consumes the next array element when there is no =, and is FAIL-CLOSED — --ftz with no determinable value is refused, because a guard that cannot tell what a flag is set to must not assume the safe answer. (Hip_rtc.fp_relaxing_option_prefixes never had this hole; it matches by prefix on options whose value is always inline.)
(name, value_semantics, why). value_semantics answers "is this setting dangerous?" given the resolved value, where None means the value could not be determined.
Names that take a value, and may therefore carry it in the NEXT array element. use_fast_math is a bare switch and is deliberately absent.
Split an nvrtc option into its name (leading dashes stripped) and inline value, if any. --ftz=true -> ("ftz", Some "true"); -use_fast_math -> ("use_fast_math", None).
val fp_scan : string list -> fp_verdict listScan a WHOLE option array, resolving values that live in a following element. Pure, so it can be exercised without libnvrtc or a device — and list-level, because the separated form is invisible to any per-element check.
The reason the option array opts must be refused, or None.
Single-element convenience wrapper. Correct only for options that carry their value inline — use fp_rejection_reason_list for anything that might be split across elements.
Reject FP-relaxing options and warn about the merely risky ones.
Applied to the WHOLE array, at the single point where an array reaches nvrtcCompileProgram, so it covers options from any source — a caller, a future environment-variable escape hatch, or a hardcoded flag added by a later maintainer — and both spellings of every value-taking option.
val nvrtc_option_array :
?arch:string ->
options:string list ->
include_opts:string list ->
unit ->
string listThe exact option array this module hands to nvrtcCompileProgram for one architecture attempt. Split out so the composition (caller options + the module's own flags) can be screened in a test, not only the caller's half — a hardcoded FP flag added here later must be caught the same way a caller's is.
Compile CUDA source to PTX.