diff --git a/cuda_core/cuda/core/_linker.pyx b/cuda_core/cuda/core/_linker.pyx index e5deeb07b10..6a077aafa2a 100644 --- a/cuda_core/cuda/core/_linker.pyx +++ b/cuda_core/cuda/core/_linker.pyx @@ -400,13 +400,13 @@ class LinkerOptions: if self.lineinfo: options.append("-lineinfo") if self.ftz is not None: - options.append(f"-ftz={'true' if self.ftz else 'false'}") + options.append(f"-ftz={'1' if self.ftz else '0'}") if self.prec_div is not None: - options.append(f"-prec-div={'true' if self.prec_div else 'false'}") + options.append(f"-prec-div={'1' if self.prec_div else '0'}") if self.prec_sqrt is not None: - options.append(f"-prec-sqrt={'true' if self.prec_sqrt else 'false'}") + options.append(f"-prec-sqrt={'1' if self.prec_sqrt else '0'}") if self.fma is not None: - options.append(f"-fma={'true' if self.fma else 'false'}") + options.append(f"-fma={'1' if self.fma else '0'}") if self.kernels_used is not None: if isinstance(self.kernels_used, str): options.append(f"-kernels-used={self.kernels_used}") @@ -428,9 +428,9 @@ class LinkerOptions: for opt in self.ptxas_options: options.append(f"-Xptxas={opt}") if self.split_compile is not None: - options.append(f"-split-compile={self.split_compile}") + options.append(f"-split-compile={int(self.split_compile)}") if self.split_compile_extended is not None: - options.append(f"-split-compile-extended={self.split_compile_extended}") + options.append(f"-split-compile-extended={int(self.split_compile_extended)}") if self.no_cache is True: options.append("-no-cache") diff --git a/cuda_core/tests/test_linker.py b/cuda_core/tests/test_linker.py index e25578c3dd1..5a7994f9110 100644 --- a/cuda_core/tests/test_linker.py +++ b/cuda_core/tests/test_linker.py @@ -206,10 +206,36 @@ def test_linker_options_as_bytes_nvjitlink(): options_str = [opt.decode() for opt in nvjitlink_options] assert "-arch=sm_80" in options_str assert "-g" in options_str - assert "-ftz=true" in options_str + assert "-ftz=1" in options_str assert "-maxrregcount=32" in options_str +@pytest.mark.agent_authored(model="claude-sonnet-5") +@pytest.mark.skipif(is_culink_backend, reason="ftz/prec_div/prec_sqrt/fma are nvjitlink-only options") +def test_linker_lto_enabled_runtime_accepts_bool_options(compile_ltoir_functions): + """Regression test for nvbug 6621758: actual LTO-enabled link, not just option setter. + + With ``link_time_optimization=True``, ``-ftz``/``-prec-div``/``-prec-sqrt``/``-fma`` + are forwarded to libnvvm and actually validated at link time, unlike in a non-LTO + link where legacy ``true``/``false`` values are silently ignored. Only ``0``/``1`` + reliably takes effect here on any CUDA version. + + The test checks that Python ``True``/``False`` values are correctly + mapped to ``1``/``0`` and accepted by the nvJitLink backend during an LTO-enabled link. + """ + options = LinkerOptions( + arch=ARCH, + link_time_optimization=True, + ftz=True, + prec_div=True, + prec_sqrt=True, + fma=True, + ) + linker = Linker(*compile_ltoir_functions, options=options) + linked_code = linker.link("cubin") + assert isinstance(linked_code, ObjectCode) + + @pytest.mark.agent_authored(model="gpt-5.6") @pytest.mark.skipif(is_culink_backend, reason="as_bytes() only supported for nvjitlink backend") @pytest.mark.parametrize("value,expected_count", [(None, 0), (False, 0), (True, 1)])