// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// SPDX-FileCopyrightText: Copyright Contributors to the Kokkos project

#ifndef KOKKOS_MACROS_HPP
#define KOKKOS_MACROS_HPP

//----------------------------------------------------------------------------
/** Pick up configure / build options via #define macros:
 *
 *  KOKKOS_ENABLE_CUDA                Kokkos::Cuda execution and memory spaces
 *  KOKKOS_ENABLE_THREADS             Kokkos::Threads execution space
 *  KOKKOS_ENABLE_HPX                 Kokkos::Experimental::HPX execution space
 *  KOKKOS_ENABLE_OPENMP              Kokkos::OpenMP execution space
 *  KOKKOS_ENABLE_HIP                 Kokkos::HIP execution space
 *  KOKKOS_ENABLE_SYCL                Kokkos::SYCL execution space
 *  KOKKOS_ENABLE_HWLOC               HWLOC library is available.
 *  KOKKOS_ENABLE_DEBUG_BOUNDS_CHECK  Insert array bounds checks, is expensive!
 */

#ifndef KOKKOS_DONT_INCLUDE_CORE_CONFIG_H
#include <KokkosCore_config.h>
#include <impl/Kokkos_DesulAtomicsConfig.hpp>
#include <impl/Kokkos_NvidiaGpuArchitectures.hpp>
#endif

#define KOKKOS_VERSION_LESS(MAJOR, MINOR, PATCH) \
  (KOKKOS_VERSION < ((MAJOR)*10000 + (MINOR)*100 + (PATCH)))

#define KOKKOS_VERSION_LESS_EQUAL(MAJOR, MINOR, PATCH) \
  (KOKKOS_VERSION <= ((MAJOR)*10000 + (MINOR)*100 + (PATCH)))

#define KOKKOS_VERSION_GREATER(MAJOR, MINOR, PATCH) \
  (KOKKOS_VERSION > ((MAJOR)*10000 + (MINOR)*100 + (PATCH)))

#define KOKKOS_VERSION_GREATER_EQUAL(MAJOR, MINOR, PATCH) \
  (KOKKOS_VERSION >= ((MAJOR)*10000 + (MINOR)*100 + (PATCH)))

#define KOKKOS_VERSION_EQUAL(MAJOR, MINOR, PATCH) \
  (KOKKOS_VERSION == ((MAJOR)*10000 + (MINOR)*100 + (PATCH)))

#if !KOKKOS_VERSION_EQUAL(KOKKOS_VERSION_MAJOR, KOKKOS_VERSION_MINOR, \
                          KOKKOS_VERSION_PATCH)
#error implementation bug
#endif

#if __has_include(<version>)
#include <version>
#else
#include <ciso646>
#endif

//----------------------------------------------------------------------------
/** Pick up compiler specific #define macros:
 *
 *  Macros for known compilers evaluate to an integral version value
 *
 *  KOKKOS_COMPILER_NVCC
 *  KOKKOS_COMPILER_GNU
 *  KOKKOS_COMPILER_INTEL_LLVM
 *  KOKKOS_COMPILER_CRAYC
 *  KOKKOS_COMPILER_APPLECC
 *  KOKKOS_COMPILER_NEXT_LLVM
 *  KOKKOS_COMPILER_CLANG
 *  KOKKOS_COMPILER_NVHPC
 *  KOKKOS_COMPILER_MSVC
 *
 *  A suite of 'KOKKOS_ENABLE_PRAGMA_...' are defined for internal use.
 *
 *  Macros for marking functions to run in an execution space:
 *
 *  KOKKOS_FUNCTION
 *  KOKKOS_INLINE_FUNCTION        request compiler to inline
 *  KOKKOS_FORCEINLINE_FUNCTION   force compiler to inline, use with care!
 */

//----------------------------------------------------------------------------

#if defined(KOKKOS_ENABLE_ATOMICS_BYPASS) &&                          \
    (defined(KOKKOS_ENABLE_THREADS) || defined(KOKKOS_ENABLE_CUDA) || \
     defined(KOKKOS_ENABLE_OPENMP) || defined(KOKKOS_ENABLE_HPX) ||   \
     defined(KOKKOS_ENABLE_HIP) || defined(KOKKOS_ENABLE_SYCL) ||     \
     defined(KOKKOS_ENABLE_OPENACC))
#error Atomics may only be disabled if neither a host parallel nor a device backend is enabled
#endif

#define KOKKOS_ENABLE_CXX11_DISPATCH_LAMBDA

#include <KokkosCore_Config_SetupBackend.hpp>

//----------------------------------------------------------------------------
// Mapping compiler built-ins to KOKKOS_COMPILER_*** macros

#if defined(__NVCC__)
// NVIDIA compiler is being used.
// Code is parsed and separated into host and device code.
// Host code is compiled again with another compiler.
// Device code is compile to 'ptx'.
// NOTE: There is no __CUDACC_VER_PATCH__ officially, its __CUDACC_VER_BUILD__
// which does have more than one digit (potentially undefined number of them).
// This macro definition is in line with our other compiler defs
#define KOKKOS_COMPILER_NVCC \
  __CUDACC_VER_MAJOR__ * 100 + __CUDACC_VER_MINOR__ * 10
#endif  // #if defined( __NVCC__ )

// #if !defined( __CUDA_ARCH__ ) // Not compiling Cuda code to 'ptx'.

// Intel compiler for host code.

#if defined(__INTEL_LLVM_COMPILER)
#define KOKKOS_COMPILER_INTEL_LLVM __INTEL_LLVM_COMPILER

// Cray compiler for device offload code
#elif defined(__cray__) && defined(__clang__)
#define KOKKOS_COMPILER_CRAY_LLVM \
  __cray_major__ * 100 + __cray_minor__ * 10 + __cray_patchlevel__

#elif defined(_CRAYC)
// CRAY compiler for host code
#define KOKKOS_COMPILER_CRAYC _CRAYC

#elif defined(__APPLE_CC__) && defined(__clang__) && \
    defined(__apple_build_version__)
#define KOKKOS_COMPILER_APPLECC __APPLE_CC__

#elif defined(__NVCOMPILER)
#define KOKKOS_COMPILER_NVHPC                                 \
  __NVCOMPILER_MAJOR__ * 10000 + __NVCOMPILER_MINOR__ * 100 + \
      __NVCOMPILER_PATCHLEVEL__

#elif defined(__NEXTSILICON__)
#define KOKKOS_COMPILER_NEXT_LLVM \
  __clang_major__ * 100 + __clang_minor__ * 10 + __clang_patchlevel__

#elif defined(__clang__)
// Check this after the Clang-based proprietary compilers which will also define
// __clang__
#define KOKKOS_COMPILER_CLANG \
  __clang_major__ * 100 + __clang_minor__ * 10 + __clang_patchlevel__

#elif defined(__GNUC__)
// Check this here because many compilers (at least Clang variants and Intel
// classic) define `__GNUC__` for compatibility
#define KOKKOS_COMPILER_GNU \
  __GNUC__ * 100 + __GNUC_MINOR__ * 10 + __GNUC_PATCHLEVEL__

#if (1040 > KOKKOS_COMPILER_GNU)
#error "Compiling with GCC version earlier than 10.4.0 is not supported."
#endif

#elif defined(_MSC_VER)
// Check this after Intel and Clang because those define _MSC_VER for
// compatibility
#define KOKKOS_COMPILER_MSVC _MSC_VER
#endif

#if defined(_OPENMP)
//  Compiling with OpenMP.
//  The value of _OPENMP is an integer value YYYYMM
//  where YYYY and MM are the year and month designation
//  of the supported OpenMP API version.
#endif  // #if defined( _OPENMP )

//----------------------------------------------------------------------------
// Intel compiler macros

#if defined(KOKKOS_COMPILER_INTEL_LLVM)
#if KOKKOS_COMPILER_INTEL_LLVM >= 20230100
#define KOKKOS_ENABLE_PRAGMA_UNROLL 1

#ifndef __SYCL_DEVICE_ONLY__
#define KOKKOS_ENABLE_PRAGMA_LOOPCOUNT 1
#define KOKKOS_ENABLE_PRAGMA_VECTOR 1
#define KOKKOS_ENABLE_PRAGMA_IVDEP 1
#endif
#endif

#if defined(_WIN32)
#define KOKKOS_RESTRICT __restrict
#else
#define KOKKOS_RESTRICT __restrict__
#endif

#ifndef KOKKOS_IMPL_ALIGN_PTR
#if defined(_WIN32)
#define KOKKOS_IMPL_ALIGN_PTR(size)
#else
#define KOKKOS_IMPL_ALIGN_PTR(size) __attribute__((align_value(size)))
#endif
#endif

#if !defined(KOKKOS_ENABLE_ASM) && !defined(_WIN32)
#define KOKKOS_ENABLE_ASM 1
#endif

#if defined(__MIC__)
// Compiling for Xeon Phi
#endif
#endif

//----------------------------------------------------------------------------
// Cray compiler macros

#if defined(KOKKOS_COMPILER_CRAYC)
#endif

//----------------------------------------------------------------------------
// CLANG compiler macros

#if defined(KOKKOS_COMPILER_CLANG)
// #define KOKKOS_ENABLE_PRAGMA_UNROLL 1
// #define KOKKOS_ENABLE_PRAGMA_IVDEP 1
// #define KOKKOS_ENABLE_PRAGMA_LOOPCOUNT 1
// #define KOKKOS_ENABLE_PRAGMA_VECTOR 1

#if !defined(KOKKOS_IMPL_ALIGN_PTR)
#define KOKKOS_IMPL_ALIGN_PTR(size) __attribute__((aligned(size)))
#endif

#endif

//----------------------------------------------------------------------------
// GNU Compiler macros

#if defined(KOKKOS_COMPILER_GNU)
// #define KOKKOS_ENABLE_PRAGMA_UNROLL 1
// #define KOKKOS_ENABLE_PRAGMA_IVDEP 1
// #define KOKKOS_ENABLE_PRAGMA_LOOPCOUNT 1
// #define KOKKOS_ENABLE_PRAGMA_VECTOR 1

#define KOKKOS_RESTRICT __restrict__

#if !defined(KOKKOS_ENABLE_ASM) && !defined(__PGIC__) &&            \
    (defined(__amd64) || defined(__amd64__) || defined(__x86_64) || \
     defined(__x86_64__) || defined(__PPC64__))
#define KOKKOS_ENABLE_ASM 1
#endif
#endif

//----------------------------------------------------------------------------
// NextLLVM compiler macros

#if defined(KOKKOS_COMPILER_NEXT_LLVM)
// #define KOKKOS_ENABLE_PRAGMA_UNROLL 1
// #define KOKKOS_ENABLE_PRAGMA_IVDEP 1
// #define KOKKOS_ENABLE_PRAGMA_LOOPCOUNT 1
// #define KOKKOS_ENABLE_PRAGMA_VECTOR 1

#if !defined(KOKKOS_IMPL_ALIGN_PTR)
#define KOKKOS_IMPL_ALIGN_PTR(size) __attribute__((aligned(size)))
#endif

#endif

//----------------------------------------------------------------------------

#if defined(KOKKOS_COMPILER_NVHPC)
#define KOKKOS_ENABLE_PRAGMA_UNROLL 1
#define KOKKOS_ENABLE_PRAGMA_IVDEP 1
// #define KOKKOS_ENABLE_PRAGMA_LOOPCOUNT 1
#define KOKKOS_ENABLE_PRAGMA_VECTOR 1
#endif

//----------------------------------------------------------------------------

#if defined(KOKKOS_COMPILER_NVCC)
#if defined(__CUDA_ARCH__)
#define KOKKOS_ENABLE_PRAGMA_UNROLL 1
#endif
#endif

//----------------------------------------------------------------------------
// Define function marking macros if compiler specific macros are undefined:

#if !defined(KOKKOS_IMPL_FORCEINLINE_ATTRIBUTE)

#if defined(__has_attribute)
#if __has_attribute(always_inline)
#define KOKKOS_IMPL_FORCEINLINE_ATTRIBUTE __attribute__((always_inline))
#endif
#endif

#if !defined(KOKKOS_IMPL_FORCEINLINE_ATTRIBUTE)
#define KOKKOS_IMPL_FORCEINLINE_ATTRIBUTE
#endif

#endif

#if !defined(KOKKOS_IMPL_HOST_FORCEINLINE_FUNCTION)
#define KOKKOS_IMPL_HOST_FORCEINLINE_FUNCTION \
  KOKKOS_IMPL_FORCEINLINE_ATTRIBUTE inline
#endif

#if !defined(KOKKOS_IMPL_FORCEINLINE_FUNCTION)
#define KOKKOS_IMPL_FORCEINLINE_FUNCTION \
  KOKKOS_IMPL_FORCEINLINE_ATTRIBUTE inline
#endif

#if !defined(KOKKOS_IMPL_INLINE_FUNCTION)
#define KOKKOS_IMPL_INLINE_FUNCTION inline
#endif

#if !defined(KOKKOS_IMPL_FUNCTION)
#define KOKKOS_IMPL_FUNCTION /**/
#endif

#if !defined(KOKKOS_INLINE_FUNCTION_DELETED)
#define KOKKOS_INLINE_FUNCTION_DELETED
#endif

#if !defined(KOKKOS_DEFAULTED_FUNCTION)
#define KOKKOS_DEFAULTED_FUNCTION
#endif

#if !defined(KOKKOS_DEDUCTION_GUIDE)
#define KOKKOS_DEDUCTION_GUIDE
#endif

#if !defined(KOKKOS_IMPL_HOST_FUNCTION)
#define KOKKOS_IMPL_HOST_FUNCTION
#endif

#if !defined(KOKKOS_IMPL_DEVICE_FUNCTION)
#define KOKKOS_IMPL_DEVICE_FUNCTION
#endif

#if !defined(KOKKOS_LAMBDA)
#define KOKKOS_LAMBDA [=]
#endif

#if !defined(KOKKOS_CLASS_LAMBDA)
#define KOKKOS_CLASS_LAMBDA [ =, *this ]
#endif

// since C++23
#if !defined(KOKKOS_ENABLE_CXX20) && !defined(__clang__) && \
    !defined(KOKKOS_COMPILER_NVCC)

// FIXME_CLANG FIXME_NVCC Clang and nvcc don't accept GNU __attribute__((...))
// in the lambda front-attr position

#if !defined(KOKKOS_FORCEINLINE_LAMBDA)
#define KOKKOS_FORCEINLINE_LAMBDA \
  KOKKOS_LAMBDA KOKKOS_IMPL_FORCEINLINE_ATTRIBUTE
#endif

#if !defined(KOKKOS_FORCEINLINE_CLASS_LAMBDA)
#define KOKKOS_FORCEINLINE_CLASS_LAMBDA \
  KOKKOS_CLASS_LAMBDA KOKKOS_IMPL_FORCEINLINE_ATTRIBUTE
#endif

#else  // C++20
       // Attributes on lambda expressions would need to go after the parameter
       // list which is not an option for us so we don't do anything.

#if !defined(KOKKOS_FORCEINLINE_LAMBDA)
#define KOKKOS_FORCEINLINE_LAMBDA KOKKOS_LAMBDA
#endif

#if !defined(KOKKOS_FORCEINLINE_CLASS_LAMBDA)
#define KOKKOS_FORCEINLINE_CLASS_LAMBDA KOKKOS_CLASS_LAMBDA
#endif

#endif

// FIXME_OPENACC
// Move to setup files once there is more content
// clang-format off
#if defined(KOKKOS_ENABLE_OPENACC)
#define KOKKOS_IMPL_RELOCATABLE_FUNCTION @"KOKKOS_RELOCATABLE_FUNCTION is not supported for the OpenACC backend"
#endif
// clang-format on

#if !defined(KOKKOS_IMPL_RELOCATABLE_FUNCTION)
#define KOKKOS_IMPL_RELOCATABLE_FUNCTION
#endif

//----------------------------------------------------------------------------
// Define final version of functions. This is so that clang tidy can find these
// macros more easily
#if defined(__clang_analyzer__)
#define KOKKOS_FUNCTION \
  KOKKOS_IMPL_FUNCTION __attribute__((annotate("KOKKOS_FUNCTION")))
#define KOKKOS_INLINE_FUNCTION \
  KOKKOS_IMPL_INLINE_FUNCTION  \
  __attribute__((annotate("KOKKOS_INLINE_FUNCTION")))
#define KOKKOS_FORCEINLINE_FUNCTION \
  KOKKOS_IMPL_FORCEINLINE_FUNCTION  \
  __attribute__((annotate("KOKKOS_FORCEINLINE_FUNCTION")))
#define KOKKOS_RELOCATABLE_FUNCTION \
  KOKKOS_IMPL_RELOCATABLE_FUNCTION  \
  __attribute__((annotate("KOKKOS_RELOCATABLE_FUNCTION")))
#else
#define KOKKOS_FUNCTION KOKKOS_IMPL_FUNCTION
#define KOKKOS_INLINE_FUNCTION KOKKOS_IMPL_INLINE_FUNCTION
#define KOKKOS_FORCEINLINE_FUNCTION KOKKOS_IMPL_FORCEINLINE_FUNCTION
#define KOKKOS_RELOCATABLE_FUNCTION KOKKOS_IMPL_RELOCATABLE_FUNCTION
#endif

//----------------------------------------------------------------------------
// Define empty macro for restrict if necessary:

#if !defined(KOKKOS_RESTRICT)
#define KOKKOS_RESTRICT
#endif

// ---------------------------------------------------------------------------
// Define macro for unreachable code:
// Only available in C++23
// FIXME_HIP doesn't support std::unreachable in device code
// FIXME_CUDA doesn't support std::unreachable in device code
#if defined(__cpp_lib_unreachable) && !defined(KOKKOS_ENABLE_HIP) && \
    !defined(KOKKOS_ENABLE_CUDA)
#include <utility>
#define KOKKOS_IMPL_UNREACHABLE() std::unreachable()
#elif defined(__has_builtin)
#if __has_builtin(__builtin_unreachable)
#define KOKKOS_IMPL_UNREACHABLE() __builtin_unreachable()
#endif
#endif

#if !defined(KOKKOS_IMPL_UNREACHABLE)
#define KOKKOS_IMPL_UNREACHABLE()
#endif

//----------------------------------------------------------------------------
// Define Macro for alignment:

#if !defined(KOKKOS_IMPL_ALIGN_PTR)
#define KOKKOS_IMPL_ALIGN_PTR(size) /* */
#endif

//----------------------------------------------------------------------------
// Determine the default execution space for parallel dispatch.
// There is zero or one default execution space specified.

#if 1 < ((defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_CUDA) ? 1 : 0) +        \
         (defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_HIP) ? 1 : 0) +         \
         (defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_SYCL) ? 1 : 0) +        \
         (defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_OPENACC) ? 1 : 0) +     \
         (defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_NEXTSILICON) ? 1 : 0) + \
         (defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_OPENMP) ? 1 : 0) +      \
         (defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_THREADS) ? 1 : 0) +     \
         (defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_HPX) ? 1 : 0) +         \
         (defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_SERIAL) ? 1 : 0))
#error "More than one KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_* specified."
#endif

// If default is not specified then chose from enabled execution spaces.
// Priority: CUDA, HIP, SYCL, OPENACC, NEXTSILICON, OPENMP, THREADS, HPX,
// SERIAL
#if defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_CUDA)
#elif defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_HIP)
#elif defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_SYCL)
#elif defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_OPENACC)
#elif defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_NEXTSILICON)
#elif defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_OPENMP)
#elif defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_THREADS)
#elif defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_HPX)
#elif defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_SERIAL)
#elif defined(KOKKOS_ENABLE_CUDA)
#define KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_CUDA
#elif defined(KOKKOS_ENABLE_HIP)
#define KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_HIP
#elif defined(KOKKOS_ENABLE_SYCL)
#define KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_SYCL
#elif defined(KOKKOS_ENABLE_OPENACC)
#define KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_OPENACC
#elif defined(KOKKOS_ENABLE_NEXTSILICON)
#define KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_NEXTSILICON
#elif defined(KOKKOS_ENABLE_OPENMP)
#define KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_OPENMP
#elif defined(KOKKOS_ENABLE_THREADS)
#define KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_THREADS
#elif defined(KOKKOS_ENABLE_HPX)
#define KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_HPX
#else
#define KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_SERIAL
#endif

//----------------------------------------------------------------------------

// Remove surrounding parentheses if present
#define KOKKOS_IMPL_STRIP_PARENS(X) KOKKOS_IMPL_ESC(KOKKOS_IMPL_ISH X)
#define KOKKOS_IMPL_ISH(...) KOKKOS_IMPL_ISH __VA_ARGS__
#define KOKKOS_IMPL_ESC(...) KOKKOS_IMPL_ESC_(__VA_ARGS__)
#define KOKKOS_IMPL_ESC_(...) KOKKOS_IMPL_VAN_##__VA_ARGS__
#define KOKKOS_IMPL_VAN_KOKKOS_IMPL_ISH

#if defined(KOKKOS_ENABLE_CUDA) && defined(KOKKOS_COMPILER_NVHPC)
#include <nv/target>
#define KOKKOS_IF_ON_DEVICE(CODE) NV_IF_TARGET(NV_IS_DEVICE, CODE)
#define KOKKOS_IF_ON_HOST(CODE) NV_IF_TARGET(NV_IS_HOST, CODE)
#endif

#ifdef KOKKOS_ENABLE_OPENACC
#ifdef KOKKOS_COMPILER_NVHPC
#define KOKKOS_IF_ON_DEVICE(CODE)   \
  if (__builtin_is_device_code()) { \
    KOKKOS_IMPL_STRIP_PARENS(CODE)  \
  }
#define KOKKOS_IF_ON_HOST(CODE)      \
  if (!__builtin_is_device_code()) { \
    KOKKOS_IMPL_STRIP_PARENS(CODE)   \
  }
#else
#include <openacc.h>
// FIXME_OPENACC acc_on_device is a non-constexpr function
#define KOKKOS_IF_ON_DEVICE(CODE)                     \
  if constexpr (acc_on_device(acc_device_not_host)) { \
    KOKKOS_IMPL_STRIP_PARENS(CODE)                    \
  }
#define KOKKOS_IF_ON_HOST(CODE)                   \
  if constexpr (acc_on_device(acc_device_host)) { \
    KOKKOS_IMPL_STRIP_PARENS(CODE)                \
  }
#endif
#endif

#ifdef KOKKOS_ENABLE_NEXTSILICON
#include <NextSilicon/Kokkos_NextSilicon_ThreadSpaceGuard.hpp>

// For grid execution, the optimizer knows __next_is_in_handed_of_code() is
// always true, in_parallel_region() will short-circuit, and not actually be
// called and the underlying flag will never be migrated to the device.
//
// During host execution the macro will check if we are in a parallel region by
// checking the flag and execute CODE only if we are IN a parallel region
// - hence we are on device!
#define KOKKOS_IF_ON_DEVICE(CODE)                                    \
  if (::Kokkos::Impl::NextSiliconThreadSpaceGuard::is_on_device()) { \
    KOKKOS_IMPL_STRIP_PARENS(CODE)                                   \
  }

// For grid execution, the optimizer knows __next_is_in_handed_of_code() is
// always true. Hence all code in KOKKOS_IF_ON_HOST will be dead code and
// optimized out. This is important to avoid unnecessary enlargening of
// the projection.
//
// For hosts execution macro will check if we are in a parallel region by
// checking the flag and execute CODE only if we are NOT IN a parallel
// region - we are on host!
#define KOKKOS_IF_ON_HOST(CODE)                                       \
  if (!::Kokkos::Impl::NextSiliconThreadSpaceGuard::is_on_device()) { \
    KOKKOS_IMPL_STRIP_PARENS(CODE)                                    \
  }
#endif

#if !defined(KOKKOS_IF_ON_HOST) && !defined(KOKKOS_IF_ON_DEVICE)
#if (defined(KOKKOS_ENABLE_CUDA) && defined(__CUDA_ARCH__)) ||         \
    (defined(KOKKOS_ENABLE_HIP) && defined(__HIP_DEVICE_COMPILE__)) || \
    (defined(KOKKOS_ENABLE_SYCL) && defined(__SYCL_DEVICE_ONLY__))
#define KOKKOS_IF_ON_DEVICE(CODE) \
  { KOKKOS_IMPL_STRIP_PARENS(CODE) }
#define KOKKOS_IF_ON_HOST(CODE) \
  {}
#else
#define KOKKOS_IF_ON_DEVICE(CODE) \
  {}
#define KOKKOS_IF_ON_HOST(CODE) \
  { KOKKOS_IMPL_STRIP_PARENS(CODE) }
#endif
#endif

//----------------------------------------------------------------------------

#define KOKKOS_INVALID_INDEX (~std::size_t(0))

#define KOKKOS_IMPL_CTOR_DEFAULT_ARG KOKKOS_INVALID_INDEX

#if defined(KOKKOS_ENABLE_DEPRECATION_WARNINGS)
#define KOKKOS_DEPRECATED [[deprecated]]
#define KOKKOS_DEPRECATED_WITH_COMMENT(comment) [[deprecated(comment)]]
#else
#define KOKKOS_DEPRECATED
#define KOKKOS_DEPRECATED_WITH_COMMENT(comment)
#endif

#define KOKKOS_IMPL_STRINGIFY(x) #x
#define KOKKOS_IMPL_TOSTRING(x) KOKKOS_IMPL_STRINGIFY(x)

#ifdef _MSC_VER
#define KOKKOS_IMPL_DO_PRAGMA(x) __pragma(x)
#define KOKKOS_IMPL_WARNING(desc) \
  KOKKOS_IMPL_DO_PRAGMA(message(  \
      __FILE__ "(" KOKKOS_IMPL_TOSTRING(__LINE__) ") : warning: " #desc))
#else
#define KOKKOS_IMPL_DO_PRAGMA(x) _Pragma(#x)
#define KOKKOS_IMPL_WARNING(desc) KOKKOS_IMPL_DO_PRAGMA(message(#desc))
#endif

// clang-format off
#if defined(__NVCOMPILER)
  #define KOKKOS_IMPL_DISABLE_DEPRECATED_WARNINGS_PUSH_() \
    _Pragma("diag_suppress 1216") \
    _Pragma("diag_suppress deprecated_entity_with_custom_message")
  #define KOKKOS_IMPL_DISABLE_DEPRECATED_WARNINGS_POP_() \
    _Pragma("diag_default 1216") \
    _Pragma("diag_default deprecated_entity_with_custom_message")
#elif defined(__EDG__)
  #define KOKKOS_IMPL_DISABLE_DEPRECATED_WARNINGS_PUSH_() \
    _Pragma("warning push")                              \
    _Pragma("warning disable 1478")
  #define KOKKOS_IMPL_DISABLE_DEPRECATED_WARNINGS_POP_() \
    _Pragma("warning pop")
#elif defined(__GNUC__) || defined(__clang__)
  #define KOKKOS_IMPL_DISABLE_DEPRECATED_WARNINGS_PUSH_() \
    _Pragma("GCC diagnostic push")                       \
    _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"")
  #define KOKKOS_IMPL_DISABLE_DEPRECATED_WARNINGS_POP_() \
    _Pragma("GCC diagnostic pop")
#elif defined(_MSC_VER)
  #define KOKKOS_IMPL_DISABLE_DEPRECATED_WARNINGS_PUSH_() \
    _Pragma("warning(push)")                             \
    _Pragma("warning(disable: 4996)")
  #define KOKKOS_IMPL_DISABLE_DEPRECATED_WARNINGS_POP_() \
    _Pragma("warning(pop)")
#else
  #define KOKKOS_IMPL_DISABLE_DEPRECATED_WARNINGS_PUSH_()
  #define KOKKOS_IMPL_DISABLE_DEPRECATED_WARNINGS_POP_()
#endif

// FIXME NVCC <13: using the deprecation warnings push/pop mechanism with nvcc
// and nvc++ as host compiler leads to bugs where some of the _Pragma are not
// taken into account.
#if defined(__NVCC__) && defined(__NVCC_DIAG_PRAGMA_SUPPORT__) && \
    (!defined(__NVCOMPILER) || (KOKKOS_COMPILER_NVCC >= 1300))
  #define KOKKOS_IMPL_DISABLE_DEPRECATED_WARNINGS_PUSH() \
    KOKKOS_IMPL_DISABLE_DEPRECATED_WARNINGS_PUSH_() \
    _Pragma("nv_diagnostic push") \
    _Pragma("nv_diag_suppress 1215,1444")
  #define KOKKOS_IMPL_DISABLE_DEPRECATED_WARNINGS_POP() \
    _Pragma("nv_diagnostic pop") \
    KOKKOS_IMPL_DISABLE_DEPRECATED_WARNINGS_POP_()
#else
  #define KOKKOS_IMPL_DISABLE_DEPRECATED_WARNINGS_PUSH() \
    KOKKOS_IMPL_DISABLE_DEPRECATED_WARNINGS_PUSH_()
  #define KOKKOS_IMPL_DISABLE_DEPRECATED_WARNINGS_POP() \
    KOKKOS_IMPL_DISABLE_DEPRECATED_WARNINGS_POP_()
#endif

#if defined(__NVCOMPILER)
#define KOKKOS_IMPL_DISABLE_UNREACHABLE_WARNINGS_PUSH() \
  _Pragma("diag_suppress code_is_unreachable")          \
  _Pragma("diag_suppress initialization_not_reachable")
#define KOKKOS_IMPL_DISABLE_UNREACHABLE_WARNINGS_POP() \
  _Pragma("diag_default code_is_unreachable")          \
  _Pragma("diag_default initialization_not_reachable")
#else
#define KOKKOS_IMPL_DISABLE_UNREACHABLE_WARNINGS_PUSH()
#define KOKKOS_IMPL_DISABLE_UNREACHABLE_WARNINGS_POP()
#endif

#if defined(__NVCC__)
#define KOKKOS_IMPL_DISABLE_CALLING_HOST_FROM_DEVICE_WARNINGS_PUSH() \
  _Pragma("nv_diag_suppress 20011, 20013, 20014, 20015")
#define KOKKOS_IMPL_DISABLE_CALLING_HOST_FROM_DEVICE_WARNINGS_POP() \
  _Pragma("nv_diag_default 20011, 20013, 20014, 20015")
#else
#define KOKKOS_IMPL_DISABLE_CALLING_HOST_FROM_DEVICE_WARNINGS_PUSH()
#define KOKKOS_IMPL_DISABLE_CALLING_HOST_FROM_DEVICE_WARNINGS_POP()
#endif
// clang-format on

#if !defined(_WIN32) && !defined(__ANDROID__)
#if __has_include(<execinfo.h>)
#define KOKKOS_IMPL_ENABLE_STACKTRACE
#endif
#if __has_include(<cxxabi.h>)
#define KOKKOS_IMPL_ENABLE_CXXABI
#endif
#endif

#if (defined(KOKKOS_IMPL_WINDOWS_CUDA) || defined(KOKKOS_COMPILER_MSVC)) && \
    !defined(KOKKOS_COMPILER_CLANG)
// MSVC (as of 16.5.5 at least) does not do empty base class optimization by
// default when there are multiple bases, even though the standard requires it
// for standard layout types.
#define KOKKOS_IMPL_ENFORCE_EMPTY_BASE_OPTIMIZATION __declspec(empty_bases)
#else
#define KOKKOS_IMPL_ENFORCE_EMPTY_BASE_OPTIMIZATION
#endif

#if defined(KOKKOS_IMPL_BUILD_SHARED_LIBS) && defined(_WIN32)
#ifdef KOKKOS_IMPL_EXPORT_SYMBOLS
#define KOKKOS_IMPL_EXPORT __declspec(dllexport)
#else
#define KOKKOS_IMPL_EXPORT __declspec(dllimport)
#endif
#else
#define KOKKOS_IMPL_EXPORT
#endif

// CUDA, HIP, and SYCL define KOKKOS_HAS_NATIVE_HALF_TYPE in their setup files
// but there isn't a correspondong file indicating support for C++23
// std::float16_t. Hence, do that detection here.
#if !defined(KOKKOS_HAS_NATIVE_HALF_TYPE) && defined(__STDCPP_FLOAT16_T__)
#define KOKKOS_HAS_NATIVE_HALF_TYPE
#define KOKKOS_IMPL_HALF_TYPE_STANDARD_SUPPORT
#define KOKKOS_HALF_IS_FULL_TYPE_ON_ARCH
#endif

#ifdef KOKKOS_HAS_NATIVE_HALF_TYPE
#define KOKKOS_HALF_T_IS_FLOAT false
#else
#define KOKKOS_HALF_T_IS_FLOAT true
#endif

#if !defined(KOKKOS_HAS_NATIVE_BHALF_TYPE) && defined(__STDCPP_BFLOAT16_T__)
#define KOKKOS_HAS_NATIVE_BHALF_TYPE
#define KOKKOS_IMPL_BHALF_TYPE_STANDARD_SUPPORT
#define KOKKOS_BHALF_IS_FULL_TYPE_ON_ARCH
#endif

#ifdef KOKKOS_HAS_NATIVE_BHALF_TYPE
#define KOKKOS_BHALF_T_IS_FLOAT false
#else
#define KOKKOS_BHALF_T_IS_FLOAT true
#endif

// check for backends that support SharedSpace and SharedHostPinnedSpace
#if !defined(KOKKOS_ENABLE_OPENACC)
#define KOKKOS_HAS_SHARED_SPACE
#endif

#if !defined(KOKKOS_ENABLE_OPENACC) && !defined(KOKKOS_ENABLE_NEXTSILICON)
#define KOKKOS_HAS_SHARED_HOST_PINNED_SPACE
#endif

#endif  // #ifndef KOKKOS_MACROS_HPP
