/* MACHINE GENERATED By Halide. */

#if !(__cplusplus >= 201103L || _MSVC_LANG >= 201103L)
#error "This code requires C++11 (or later); please upgrade your compiler."
#endif

#include <assert.h>
#include <fenv.h>
#include <float.h>
#include <limits.h>
#include <math.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <type_traits>

extern "C" {
int64_t halide_current_time_ns(void *ctx);
void halide_profiler_pipeline_end(void *, void *);
struct halide_buffer_t;
char *halide_buffer_to_string(char *, char *, const halide_buffer_t *);
}

#ifdef _WIN32
#ifndef _MT
__declspec(dllimport) float __cdecl roundf(float);
__declspec(dllimport) double __cdecl round(double);
#endif
#else
inline float asinh_f32(float x) {
    return asinhf(x);
}
inline float acosh_f32(float x) {
    return acoshf(x);
}
inline float atanh_f32(float x) {
    return atanhf(x);
}
inline double asinh_f64(double x) {
    return asinh(x);
}
inline double acosh_f64(double x) {
    return acosh(x);
}
inline double atanh_f64(double x) {
    return atanh(x);
}
#endif
inline float sqrt_f32(float x) {
    return sqrtf(x);
}
inline float sin_f32(float x) {
    return sinf(x);
}
inline float asin_f32(float x) {
    return asinf(x);
}
inline float cos_f32(float x) {
    return cosf(x);
}
inline float acos_f32(float x) {
    return acosf(x);
}
inline float tan_f32(float x) {
    return tanf(x);
}
inline float atan_f32(float x) {
    return atanf(x);
}
inline float atan2_f32(float x, float y) {
    return atan2f(x, y);
}
inline float sinh_f32(float x) {
    return sinhf(x);
}
inline float cosh_f32(float x) {
    return coshf(x);
}
inline float tanh_f32(float x) {
    return tanhf(x);
}
inline float hypot_f32(float x, float y) {
    return hypotf(x, y);
}
inline float exp_f32(float x) {
    return expf(x);
}
inline float log_f32(float x) {
    return logf(x);
}
inline float pow_f32(float x, float y) {
    return powf(x, y);
}
inline float floor_f32(float x) {
    return floorf(x);
}
inline float ceil_f32(float x) {
    return ceilf(x);
}

inline double sqrt_f64(double x) {
    return sqrt(x);
}
inline double sin_f64(double x) {
    return sin(x);
}
inline double asin_f64(double x) {
    return asin(x);
}
inline double cos_f64(double x) {
    return cos(x);
}
inline double acos_f64(double x) {
    return acos(x);
}
inline double tan_f64(double x) {
    return tan(x);
}
inline double atan_f64(double x) {
    return atan(x);
}
inline double atan2_f64(double x, double y) {
    return atan2(x, y);
}
inline double sinh_f64(double x) {
    return sinh(x);
}
inline double cosh_f64(double x) {
    return cosh(x);
}
inline double tanh_f64(double x) {
    return tanh(x);
}
inline double hypot_f64(double x, double y) {
    return hypot(x, y);
}
inline double exp_f64(double x) {
    return exp(x);
}
inline double log_f64(double x) {
    return log(x);
}
inline double pow_f64(double x, double y) {
    return pow(x, y);
}
inline double floor_f64(double x) {
    return floor(x);
}
inline double ceil_f64(double x) {
    return ceil(x);
}

inline float nan_f32() {
    return NAN;
}
inline float neg_inf_f32() {
    return -INFINITY;
}
inline float inf_f32() {
    return INFINITY;
}
inline bool is_nan_f32(float x) {
    return isnan(x);
}
inline bool is_nan_f64(double x) {
    return isnan(x);
}
inline bool is_inf_f32(float x) {
    return isinf(x);
}
inline bool is_inf_f64(double x) {
    return isinf(x);
}
inline bool is_finite_f32(float x) {
    return isfinite(x);
}
inline bool is_finite_f64(double x) {
    return isfinite(x);
}

template<typename A, typename B>
inline A reinterpret(const B &b) {
    static_assert(sizeof(A) == sizeof(B), "type size mismatch");
    A a;
    memcpy(&a, &b, sizeof(a));
    return a;
}

inline float float_from_bits(uint32_t bits) {
    return reinterpret<float, uint32_t>(bits);
}

template<typename T>
inline int halide_popcount_fallback(T a) {
    int bits_set = 0;
    while (a != 0) {
        bits_set += 1;
        // See: https://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetKernighan
        a &= a - 1;
    }
    return bits_set;
}

template<typename T>
inline int halide_popcount(T a) {
    return halide_popcount_fallback<T>(a);
}

template<>
inline int halide_popcount<uint64_t>(uint64_t a) {
#ifdef _MSC_VER
#if defined(_WIN64)
    return __popcnt64(a);
#else
    return __popcnt((uint32_t)(a >> 32)) + __popcnt((uint32_t)(a & 0xffffffff));
#endif
#else
#if defined(__builtin_popcountll)
    static_assert(sizeof(unsigned long long) >= sizeof(uint64_t), "");
    return return __builtin_popcountll(a);
#else
    return halide_popcount_fallback<uint64_t>(a);
#endif
#endif
}

template<typename T>
inline int halide_count_leading_zeros(T a) {
    int leading_zeros = 0;
    int bit = sizeof(a) * 8 - 1;
    while (bit >= 0 && (a & (((T)1) << bit)) == 0) {
        leading_zeros++;
        bit--;
    }
    return leading_zeros;
}

template<typename T>
inline int halide_count_trailing_zeros(T a) {
    int trailing_zeros = 0;
    constexpr int bits = sizeof(a) * 8;
    int bit = 0;
    while (bit < bits && (a & (((T)1) << bit)) == 0) {
        trailing_zeros++;
        bit++;
    }
    return trailing_zeros;
}

template<typename T>
inline T halide_cpp_max(const T &a, const T &b) {
    return (a > b) ? a : b;
}

template<typename T>
inline T halide_cpp_min(const T &a, const T &b) {
    return (a < b) ? a : b;
}

template<typename T>
inline void halide_maybe_unused(const T &) {
}

template<typename A, typename B>
const B &return_second(const A &a, const B &b) {
    halide_maybe_unused(a);
    return b;
}

namespace {
template<void (*FreeFn)(void *, void *)>
class HalideFreeHelper {
    void *const user_context;
    void *ptr;

public:
    HalideFreeHelper(void *user_context, void *ptr)
        : user_context(user_context), ptr(ptr) {
    }
    ~HalideFreeHelper() {
        free();
    }
    void free() {
        if (ptr) {
            FreeFn(user_context, ptr);
            ptr = nullptr;
        }
    }
};

}  // namespace
