/**
 * vec - a tiny SIMD vector library in C99
 * 
 * Copyright (c) 2024 Paper
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
**/

#ifndef VEC_VEC_H_
#define VEC_VEC_H_

#define VEC_SEMVER_ATLEAST(a, b, c, x, y, z) \
	(((a) >= (x)) && \
	 ((a) > x || (b) >= (y)) && \
	 ((a) > x || (b) > (y) || (c) >= (z)))

#define VEC_GCC_ATLEAST(x, y, z) \
	VEC_SEMVER_ATLEAST(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__, x, y, z)

/* GCC/clang attributes */
#if defined(__has_attribute)
# if __has_attribute(__always_inline__)
#  define VEC_ALWAYS_INLINE __attribute__((__always_inline__))
# endif
# if __has_attribute(__aligned__)
#  define VEC_ALIGNED(x) __attribute__((__aligned__(x)))
# endif
# if __has_attribute(__vector_size__)
#  define VEC_HAVE_GCC_VECTORS
# endif
#endif

#ifndef VEC_HAVE_GCC_VECTORS
# if __GNUC__ >= 4 || __clang_major__ >= 3
#  define VEC_HAVE_GCC_VECTORS
# endif
#endif

#ifndef VEC_ALIGNED
# if VEC_GCC_ATLEAST(2, 7, 0)
#  define VEC_ALIGNED(x) __attribute__((aligned(x)))
# endif
#endif

#ifndef VEC_ALWAYS_INLINE
# if VEC_GCC_ATLEAST(3, 1, 0)
#  define VEC_ALWAYS_INLINE(x) __attribute__((always_inline))
# endif
#endif

#ifndef VEC_ALWAYS_INLINE
# define VEC_ALWAYS_INLINE
#endif

#ifdef VEC_ALIGNED
# define VEC_ALIGNED_ARRAY(type, var, size, align) \
	VEC_ALIGNED(align) type var[size]
#else
/* allocate more than necessary to align */
# define VEC_ALIGNED_ARRAY(type, var, size, align) \
	type var##_unaligned_[size + align - 1]; \
	type *var = (type *)((((intptr_t)var##_unaligned_ + align - 1) / align) * align)
#endif

/* POWER altivec */
#ifdef __ALTIVEC__
# include "impl/altivec.h"
#endif

/* x86_64 SSE2+ */
#ifdef __SSE2__
# include "impl/sse2.h"
#endif

#ifdef VEC_HAVE_GCC_VECTORS
# include "impl/gcc.h"
#endif

#include "impl/generic.h"

#endif /* VEC_VEC_H_ */
