
/*
 * Copyright (C) Igor Sysoev
 * Copyright (C) NGINX, Inc.
 */

#ifndef _NJS_CLANG_H_INCLUDED_
#define _NJS_CLANG_H_INCLUDED_


#include <stdarg.h>
#include <stddef.h>       /* offsetof(). */


#define njs_inline         static inline __attribute__((always_inline))
#define njs_noinline       __attribute__((noinline))
#define njs_cdecl


#define njs_container_of(p, type, field)                                      \
    (type *) ((u_char *) (p) - offsetof(type, field))

#define njs_nitems(x)                                                         \
    (sizeof(x) / sizeof((x)[0]))

#define njs_max(val1, val2)                                                   \
    ((val1 < val2) ? (val2) : (val1))

#define njs_min(val1, val2)                                                   \
    ((val1 < val2) ? (val1) : (val2))


#if (NJS_HAVE_BUILTIN_EXPECT)
#define njs_expect(c, x)   __builtin_expect((long) (x), (c))
#define njs_fast_path(x)   njs_expect(1, x)
#define njs_slow_path(x)   njs_expect(0, x)

#else
#define njs_expect(c, x)   (x)
#define njs_fast_path(x)   (x)
#define njs_slow_path(x)   (x)
#endif


#if (NJS_HAVE_BUILTIN_UNREACHABLE)
#define njs_unreachable()  __builtin_unreachable()

#else
#define njs_unreachable()
#endif


#if (NJS_HAVE_BUILTIN_PREFETCH)
#define njs_prefetch(a)    __builtin_prefetch(a)

#else
#define njs_prefetch(a)
#endif


#if (NJS_HAVE_BUILTIN_CLZ)
#define njs_leading_zeros(x)  (((x) == 0) ? 32 : __builtin_clz(x))

#else

njs_inline uint32_t
njs_leading_zeros(uint32_t x)
{
    uint32_t  n;

    /*
     * There is no sense to optimize this function, since almost
     * all platforms nowadays support the built-in instruction.
     */

    if (x == 0) {
        return 32;
    }

    n = 0;

    while ((x & 0x80000000) == 0) {
        n++;
        x <<= 1;
    }

    return n;
}

#endif


#if (NJS_HAVE_BUILTIN_CLZLL)
#define njs_leading_zeros64(x)  (((x) == 0) ? 64 : __builtin_clzll(x))

#else

njs_inline uint64_t
njs_leading_zeros64(uint64_t x)
{
    uint64_t  n;

    /*
     * There is no sense to optimize this function, since almost
     * all platforms nowadays support the built-in instruction.
     */

    if (x == 0) {
        return 64;
    }

    n = 0;

    while ((x & 0x8000000000000000ULL) == 0) {
        n++;
        x <<= 1;
    }

    return n;
}

#endif


#if (NJS_HAVE_GCC_ATTRIBUTE_VISIBILITY)
#define NJS_EXPORT         __attribute__((visibility("default")))

#else
#define NJS_EXPORT
#endif


#if (NJS_HAVE_GCC_ATTRIBUTE_ALIGNED)
#define njs_aligned(x)     __attribute__((aligned(x)))

#else
#define njs_aligned(x)
#endif


#if (NJS_HAVE_GCC_ATTRIBUTE_PACKED)
#define NJS_PACKED    __attribute__((packed))

#else
#define NJS_PACKED
#endif


#if (NJS_HAVE_GCC_ATTRIBUTE_FALLTHROUGH)
#define NJS_FALLTHROUGH    __attribute__((fallthrough))

#else
#define NJS_FALLTHROUGH
#endif


#if (NJS_HAVE_GCC_ATTRIBUTE_MALLOC)
#define NJS_MALLOC_LIKE    __attribute__((__malloc__))

#else
#define NJS_MALLOC_LIKE
#endif


#if (NJS_CLANG)
/* Any __asm__ directive disables loop vectorization in GCC and Clang. */
#define njs_pragma_loop_disable_vectorization  __asm__("")

#else
#define njs_pragma_loop_disable_vectorization
#endif


#define njs_stringify(v)    #v


#if (NJS_HAVE_MEMORY_SANITIZER)
#include <sanitizer/msan_interface.h>

#define njs_msan_unpoison(ptr, size)  __msan_unpoison(ptr, size)
#else

#define njs_msan_unpoison(ptr, size)
#endif

#if (NJS_HAVE_GCC_ATTRIBUTE_NO_SANITIZE)
#define NJS_NOSANITIZE(options) __attribute__((no_sanitize(options)))
#else
#define NJS_NOSANITIZE(options)
#endif


njs_inline NJS_NOSANITIZE("float-cast-overflow") int64_t
njs_unsafe_cast_double_to_int64(double num)
{
    /*
     * Casting NaN to integer is undefined behavior,
     * but it is fine in some cases where we do additional checks later.
     * For example:
     *  int64_t i64 = njs_unsafe_cast_double_to_int64(num);
     *  if (i64 == num) {
     *    // num is integer
     *  }
     *
     * We do this as inline function to avoid UndefinedBehaviorSanitizer
     * warnings.
     */
    return (int64_t) num;
}


#if (NJS_HAVE_DENORMALS_CONTROL)
#include <xmmintrin.h>

/*
 * 0x8000 Flush to zero
 * 0x0040 Denormals are zeros
 */

#define NJS_MM_DENORMALS_MASK 0x8040

#define njs_mm_denormals(on)                                                  \
    _mm_setcsr((_mm_getcsr() & ~NJS_MM_DENORMALS_MASK) | (!(on) ? 0x8040: 0x0))
#else

#define njs_mm_denormals(on)
#endif


#ifndef NJS_MAX_ALIGNMENT

#if (NJS_SOLARIS)
/* x86_64: 16, i386: 4, sparcv9: 16, sparcv8: 8. */
#define NJS_MAX_ALIGNMENT  _MAX_ALIGNMENT

#elif (NJS_WINDOWS)
/* Win64: 16, Win32: 8. */
#define NJS_MAX_ALIGNMENT  MEMORY_ALLOCATION_ALIGNMENT

#elif (__amd64__)
#define NJS_MAX_ALIGNMENT  16

#elif (__i386__ || __i386)
#define NJS_MAX_ALIGNMENT  4

#elif (__arm__)
#define NJS_MAX_ALIGNMENT  16

#else
#define NJS_MAX_ALIGNMENT  16
#endif

#endif


#define njs_align_size(size, a)                                               \
    (((size) + ((size_t) (a) - 1)) & ~((size_t) (a) - 1))


#define njs_align_ptr(p, a)                                                   \
    (u_char *) (((uintptr_t) (p) + ((uintptr_t) (a) - 1))                     \
                 & ~((uintptr_t) (a) - 1))

#define njs_trunc_ptr(p, a)                                                   \
    (u_char *) ((uintptr_t) (p) & ~((uintptr_t) (a) - 1))


#endif /* _NJS_CLANG_H_INCLUDED_ */
