From 2b534ce74edb7cea4323ee6e8d8f77ae4fd64cc9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 17 Feb 2026 18:47:51 +0000 Subject: [PATCH 1/7] Initial plan From 1c2ec9e748421e39e39415c2a72ea693dbbc465c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 17 Feb 2026 18:51:23 +0000 Subject: [PATCH 2/7] Extend constexpr Context documentation with ODR violation details and examples Co-authored-by: crtrott <9490481+crtrott@users.noreply.github.com> --- .../macros-special/if_on_host_or_device.rst | 129 +++++++++++++++++- 1 file changed, 127 insertions(+), 2 deletions(-) diff --git a/docs/source/API/core/macros-special/if_on_host_or_device.rst b/docs/source/API/core/macros-special/if_on_host_or_device.rst index 2d50e0a88..05bc97af5 100644 --- a/docs/source/API/core/macros-special/if_on_host_or_device.rst +++ b/docs/source/API/core/macros-special/if_on_host_or_device.rst @@ -92,8 +92,133 @@ accessible outside of it. ``constexpr`` Context --------------------- -These macros cannot be used in a context that requires a ``constexpr`` -(constant expression). +These macros **must not** be used in a context that requires a ``constexpr`` +(constant expression). Using ``KOKKOS_IF_ON_HOST`` or ``KOKKOS_IF_ON_DEVICE`` +within ``constexpr`` functions or to initialize ``constexpr`` variables leads to +**One Definition Rule (ODR) violations** and undefined behavior. + +Why This Is Problematic +^^^^^^^^^^^^^^^^^^^^^^^^ + +Unlike runtime function calls, ``constexpr`` functions and variables generate +compile-time values that can affect the structure of types, the size of objects, +and template instantiations. When ``KOKKOS_IF_ON_HOST`` and +``KOKKOS_IF_ON_DEVICE`` are used in ``constexpr`` contexts, they cause the same +function or variable to have different compile-time values on the host versus +the device—similar to using architecture-specific preprocessor macros like +``#ifdef __AVX2__`` in different translation units. + +This is analogous to the following problematic pattern: + +.. code-block:: cpp + + // DO NOT DO THIS - ODR violation + static constexpr int foo() { + #ifdef __AVX2__ + return 4; + #else + return 2; + #endif + } + +If you compile this code in two different translation units with different +compiler flags (one with AVX2 and one without) and then link them together, you +have an ODR violation because the same function has different definitions. + +The same principle applies to host/device compilation: a ``constexpr`` function +that returns different values on host and device violates the ODR. + +Examples of ODR Violations +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +**Problematic: Using in** ``constexpr`` **function** + +.. code-block:: cpp + + // DO NOT DO THIS - causes ODR violation + static constexpr KOKKOS_FUNCTION int compute_block_size() { + KOKKOS_IF_ON_HOST((return 4;)) + KOKKOS_IF_ON_DEVICE((return 2;)) + } + + struct Functor { + int data[compute_block_size()]; // Size differs on host vs device! + // This creates an ODR violation and undefined behavior + }; + +In this example, the ``Functor`` struct would have different sizes on the host +and device, causing serious memory corruption issues when passed between them. + +**Problematic: Lambda captures with** ``constexpr`` **usage** + +.. code-block:: cpp + + // DO NOT DO THIS - causes ODR violation + void foo() { + int a = 0; + double b = 1.0; + auto lambda = KOKKOS_LAMBDA(int) { + KOKKOS_IF_ON_HOST((printf("%i\n", a);)) // Captures 'a' (4 bytes) + KOKKOS_IF_ON_DEVICE((printf("%lf\n", b);)) // Captures 'b' (8 bytes) + }; + // Lambda has different size on host (4 bytes) vs device (8 bytes) + } + +The lambda object has different sizes on host and device because of the +different captures, violating the ODR. + +Correct Alternatives +^^^^^^^^^^^^^^^^^^^^ + +**Alternative 1: Use non-**``constexpr`` **runtime function** + +If the value doesn't need to be a compile-time constant, simply remove +``constexpr``: + +.. code-block:: cpp + + // This is OK - runtime function + static KOKKOS_FUNCTION int compute_block_size() { + KOKKOS_IF_ON_HOST((return 4;)) + KOKKOS_IF_ON_DEVICE((return 2;)) + } + +**Alternative 2: Move** ``KOKKOS_IF_ON_*`` **to calling context** + +If you need compile-time constants, move the conditional compilation up one +level: + +.. code-block:: cpp + + // This is OK - separate constexpr values in each branch + KOKKOS_INLINE_FUNCTION void process() { + KOKKOS_IF_ON_HOST(( + constexpr int block_size = 4; + // Use block_size here... + )) + KOKKOS_IF_ON_DEVICE(( + constexpr int block_size = 2; + // Use block_size here... + )) + } + +**Alternative 3: Use template specialization** + +For more complex cases, consider using template specialization on execution +spaces: + +.. code-block:: cpp + + // This is OK - different specializations + template + struct BlockSize { + static constexpr int value = 2; // Default for devices + }; + + template<> + struct BlockSize { + static constexpr int value = 4; // Specialized for host + }; Best Practices -------------- From d5dd700199efae178c2bc516a27fed2e7fbd1ffc Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 17 Feb 2026 18:52:59 +0000 Subject: [PATCH 3/7] Fix template specialization example to use execution space instead of memory space Co-authored-by: crtrott <9490481+crtrott@users.noreply.github.com> --- docs/source/API/core/macros-special/if_on_host_or_device.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/API/core/macros-special/if_on_host_or_device.rst b/docs/source/API/core/macros-special/if_on_host_or_device.rst index 05bc97af5..38f0ff6ba 100644 --- a/docs/source/API/core/macros-special/if_on_host_or_device.rst +++ b/docs/source/API/core/macros-special/if_on_host_or_device.rst @@ -216,7 +216,7 @@ spaces: }; template<> - struct BlockSize { + struct BlockSize { static constexpr int value = 4; // Specialized for host }; From 9ddc87e21f68143ff4ef8293c022c9572091d79d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 17 Feb 2026 18:53:37 +0000 Subject: [PATCH 4/7] Remove platform-specific size assumptions from lambda capture example Co-authored-by: crtrott <9490481+crtrott@users.noreply.github.com> --- .../source/API/core/macros-special/if_on_host_or_device.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/source/API/core/macros-special/if_on_host_or_device.rst b/docs/source/API/core/macros-special/if_on_host_or_device.rst index 38f0ff6ba..741a6753d 100644 --- a/docs/source/API/core/macros-special/if_on_host_or_device.rst +++ b/docs/source/API/core/macros-special/if_on_host_or_device.rst @@ -158,10 +158,10 @@ and device, causing serious memory corruption issues when passed between them. int a = 0; double b = 1.0; auto lambda = KOKKOS_LAMBDA(int) { - KOKKOS_IF_ON_HOST((printf("%i\n", a);)) // Captures 'a' (4 bytes) - KOKKOS_IF_ON_DEVICE((printf("%lf\n", b);)) // Captures 'b' (8 bytes) + KOKKOS_IF_ON_HOST((printf("%i\n", a);)) // Captures 'a' + KOKKOS_IF_ON_DEVICE((printf("%lf\n", b);)) // Captures 'b' }; - // Lambda has different size on host (4 bytes) vs device (8 bytes) + // Lambda has different size on host vs device due to different captures } The lambda object has different sizes on host and device because of the From c160bf909f98071125fb47ec7d1bcd8a450fed95 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 17 Feb 2026 19:11:26 +0000 Subject: [PATCH 5/7] Address review feedback: update section titles and emphasize template specialization preference Co-authored-by: crtrott <9490481+crtrott@users.noreply.github.com> --- .../source/API/core/macros-special/if_on_host_or_device.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/source/API/core/macros-special/if_on_host_or_device.rst b/docs/source/API/core/macros-special/if_on_host_or_device.rst index 741a6753d..9d3d3ba60 100644 --- a/docs/source/API/core/macros-special/if_on_host_or_device.rst +++ b/docs/source/API/core/macros-special/if_on_host_or_device.rst @@ -149,7 +149,7 @@ Examples of ODR Violations In this example, the ``Functor`` struct would have different sizes on the host and device, causing serious memory corruption issues when passed between them. -**Problematic: Lambda captures with** ``constexpr`` **usage** +**Problematic: Lambda capture dependency** .. code-block:: cpp @@ -202,9 +202,9 @@ level: )) } -**Alternative 3: Use template specialization** +**Alternative 3 (Preferred): Use template specialization** -For more complex cases, consider using template specialization on execution +If possible use template specialization on execution spaces: .. code-block:: cpp From e90a4fe92324c4e15bcca6496c3644eabe4f16e8 Mon Sep 17 00:00:00 2001 From: Christian Trott Date: Mon, 9 Mar 2026 16:52:59 -0600 Subject: [PATCH 6/7] Update based on reviews Signed-off-by: Christian Trott --- .../macros-special/if_on_host_or_device.rst | 64 +++++++------------ 1 file changed, 22 insertions(+), 42 deletions(-) diff --git a/docs/source/API/core/macros-special/if_on_host_or_device.rst b/docs/source/API/core/macros-special/if_on_host_or_device.rst index 9d3d3ba60..a7dccc607 100644 --- a/docs/source/API/core/macros-special/if_on_host_or_device.rst +++ b/docs/source/API/core/macros-special/if_on_host_or_device.rst @@ -104,29 +104,8 @@ Unlike runtime function calls, ``constexpr`` functions and variables generate compile-time values that can affect the structure of types, the size of objects, and template instantiations. When ``KOKKOS_IF_ON_HOST`` and ``KOKKOS_IF_ON_DEVICE`` are used in ``constexpr`` contexts, they cause the same -function or variable to have different compile-time values on the host versus -the device—similar to using architecture-specific preprocessor macros like -``#ifdef __AVX2__`` in different translation units. - -This is analogous to the following problematic pattern: - -.. code-block:: cpp - - // DO NOT DO THIS - ODR violation - static constexpr int foo() { - #ifdef __AVX2__ - return 4; - #else - return 2; - #endif - } - -If you compile this code in two different translation units with different -compiler flags (one with AVX2 and one without) and then link them together, you -have an ODR violation because the same function has different definitions. - -The same principle applies to host/device compilation: a ``constexpr`` function -that returns different values on host and device violates the ODR. +function or variable to have different compile-time values or types on the host versus +the device, potentially leading to ODR violations. Examples of ODR Violations ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -170,7 +149,25 @@ different captures, violating the ODR. Correct Alternatives ^^^^^^^^^^^^^^^^^^^^ -**Alternative 1: Use non-**``constexpr`` **runtime function** +**Alternative 1 (Preferred): Use template specialization** + +If possible use template specialization on execution +spaces: + +.. code-block:: cpp + + // This is OK - different specializations + template + struct BlockSize { + static constexpr int value = 2; // Default for devices + }; + + template<> + struct BlockSize { + static constexpr int value = 4; // Specialized for host + }; + +**Alternative 2: Use non-**``constexpr`` **runtime function** If the value doesn't need to be a compile-time constant, simply remove ``constexpr``: @@ -183,7 +180,7 @@ If the value doesn't need to be a compile-time constant, simply remove KOKKOS_IF_ON_DEVICE((return 2;)) } -**Alternative 2: Move** ``KOKKOS_IF_ON_*`` **to calling context** +**Alternative 3: Move** ``KOKKOS_IF_ON_*`` **to calling context** If you need compile-time constants, move the conditional compilation up one level: @@ -202,23 +199,6 @@ level: )) } -**Alternative 3 (Preferred): Use template specialization** - -If possible use template specialization on execution -spaces: - -.. code-block:: cpp - - // This is OK - different specializations - template - struct BlockSize { - static constexpr int value = 2; // Default for devices - }; - - template<> - struct BlockSize { - static constexpr int value = 4; // Specialized for host - }; Best Practices -------------- From 3dd7d9a7a78597ad0781f74e2c95aded49a08071 Mon Sep 17 00:00:00 2001 From: Christian Trott Date: Mon, 9 Mar 2026 17:08:31 -0600 Subject: [PATCH 7/7] Add another one Signed-off-by: Christian Trott --- docs/source/API/core/macros-special/if_on_host_or_device.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/API/core/macros-special/if_on_host_or_device.rst b/docs/source/API/core/macros-special/if_on_host_or_device.rst index a7dccc607..5070f4edf 100644 --- a/docs/source/API/core/macros-special/if_on_host_or_device.rst +++ b/docs/source/API/core/macros-special/if_on_host_or_device.rst @@ -94,7 +94,7 @@ accessible outside of it. These macros **must not** be used in a context that requires a ``constexpr`` (constant expression). Using ``KOKKOS_IF_ON_HOST`` or ``KOKKOS_IF_ON_DEVICE`` -within ``constexpr`` functions or to initialize ``constexpr`` variables leads to +within ``constexpr`` functions or to initialize ``constexpr`` variables can lead to **One Definition Rule (ODR) violations** and undefined behavior. Why This Is Problematic