1/****************************************************************************
2 * Copyright (C) 2017 Intel Corporation.   All Rights Reserved.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 ****************************************************************************/
23#pragma once
24
25#include "simdlib_types.hpp"
26
27// For documentation, please see the following include...
28// #include "simdlib_interface.hpp"
29
30namespace SIMDImpl
31{
32    namespace SIMD128Impl
33    {
34#if SIMD_ARCH >= SIMD_ARCH_AVX
35        struct AVXImpl
36        {
37#define __SIMD_LIB_AVX_HPP__
38#include "simdlib_128_avx.inl"
39#undef __SIMD_LIB_AVX_HPP__
40        }; // struct AVXImpl
41#endif     // #if SIMD_ARCH >= SIMD_ARCH_AVX
42
43#if SIMD_ARCH >= SIMD_ARCH_AVX2
44        struct AVX2Impl : AVXImpl
45        {
46#define __SIMD_LIB_AVX2_HPP__
47#include "simdlib_128_avx2.inl"
48#undef __SIMD_LIB_AVX2_HPP__
49        }; // struct AVX2Impl
50#endif     // #if SIMD_ARCH >= SIMD_ARCH_AVX2
51
52#if SIMD_ARCH >= SIMD_ARCH_AVX512
53        struct AVX512Impl : AVX2Impl
54        {
55#if defined(SIMD_OPT_128_AVX512)
56#define __SIMD_LIB_AVX512_HPP__
57#include "simdlib_128_avx512.inl"
58#if defined(SIMD_ARCH_KNIGHTS)
59#include "simdlib_128_avx512_knights.inl"
60#else // optimize for core
61#include "simdlib_128_avx512_core.inl"
62#endif // defined(SIMD_ARCH_KNIGHTS)
63#undef __SIMD_LIB_AVX512_HPP__
64#endif     // SIMD_OPT_128_AVX512
65        }; // struct AVX2Impl
66#endif     // #if SIMD_ARCH >= SIMD_ARCH_AVX512
67
68        struct Traits : SIMDImpl::Traits
69        {
70#if SIMD_ARCH == SIMD_ARCH_AVX
71            using IsaImpl = AVXImpl;
72#elif SIMD_ARCH == SIMD_ARCH_AVX2
73            using IsaImpl = AVX2Impl;
74#elif SIMD_ARCH == SIMD_ARCH_AVX512
75            using IsaImpl = AVX512Impl;
76#else
77#error Invalid value for SIMD_ARCH
78#endif
79
80            using Float   = SIMD128Impl::Float;
81            using Double  = SIMD128Impl::Double;
82            using Integer = SIMD128Impl::Integer;
83            using Vec4    = SIMD128Impl::Vec4;
84            using Mask    = SIMD128Impl::Mask;
85        };
86    } // namespace SIMD128Impl
87
88    namespace SIMD256Impl
89    {
90#if SIMD_ARCH >= SIMD_ARCH_AVX
91        struct AVXImpl
92        {
93#define __SIMD_LIB_AVX_HPP__
94#include "simdlib_256_avx.inl"
95#undef __SIMD_LIB_AVX_HPP__
96        }; // struct AVXImpl
97#endif     // #if SIMD_ARCH >= SIMD_ARCH_AVX
98
99#if SIMD_ARCH >= SIMD_ARCH_AVX2
100        struct AVX2Impl : AVXImpl
101        {
102#define __SIMD_LIB_AVX2_HPP__
103#include "simdlib_256_avx2.inl"
104#undef __SIMD_LIB_AVX2_HPP__
105        }; // struct AVX2Impl
106#endif     // #if SIMD_ARCH >= SIMD_ARCH_AVX2
107
108#if SIMD_ARCH >= SIMD_ARCH_AVX512
109        struct AVX512Impl : AVX2Impl
110        {
111#if defined(SIMD_OPT_256_AVX512)
112#define __SIMD_LIB_AVX512_HPP__
113#include "simdlib_256_avx512.inl"
114#if defined(SIMD_ARCH_KNIGHTS)
115#include "simdlib_256_avx512_knights.inl"
116#else // optimize for core
117#include "simdlib_256_avx512_core.inl"
118#endif // defined(SIMD_ARCH_KNIGHTS)
119#undef __SIMD_LIB_AVX512_HPP__
120#endif     // SIMD_OPT_256_AVX512
121        }; // struct AVX2Impl
122#endif     // #if SIMD_ARCH >= SIMD_ARCH_AVX512
123
124        struct Traits : SIMDImpl::Traits
125        {
126#if SIMD_ARCH == SIMD_ARCH_AVX
127            using IsaImpl = AVXImpl;
128#elif SIMD_ARCH == SIMD_ARCH_AVX2
129            using IsaImpl = AVX2Impl;
130#elif SIMD_ARCH == SIMD_ARCH_AVX512
131            using IsaImpl = AVX512Impl;
132#else
133#error Invalid value for SIMD_ARCH
134#endif
135
136            using Float   = SIMD256Impl::Float;
137            using Double  = SIMD256Impl::Double;
138            using Integer = SIMD256Impl::Integer;
139            using Vec4    = SIMD256Impl::Vec4;
140            using Mask    = SIMD256Impl::Mask;
141        };
142    } // namespace SIMD256Impl
143
144    namespace SIMD512Impl
145    {
146#if SIMD_ARCH >= SIMD_ARCH_AVX
147        template <typename SIMD256T>
148        struct AVXImplBase
149        {
150#define __SIMD_LIB_AVX_HPP__
151#include "simdlib_512_emu.inl"
152#include "simdlib_512_emu_masks.inl"
153#undef __SIMD_LIB_AVX_HPP__
154        }; // struct AVXImplBase
155        using AVXImpl = AVXImplBase<SIMD256Impl::AVXImpl>;
156#endif // #if SIMD_ARCH >= SIMD_ARCH_AVX
157
158#if SIMD_ARCH >= SIMD_ARCH_AVX2
159        using AVX2Impl = AVXImplBase<SIMD256Impl::AVX2Impl>;
160#endif // #if SIMD_ARCH >= SIMD_ARCH_AVX2
161
162#if SIMD_ARCH >= SIMD_ARCH_AVX512
163        struct AVX512Impl : AVXImplBase<SIMD256Impl::AVX512Impl>
164        {
165#define __SIMD_LIB_AVX512_HPP__
166#include "simdlib_512_avx512.inl"
167#include "simdlib_512_avx512_masks.inl"
168#if defined(SIMD_ARCH_KNIGHTS)
169#include "simdlib_512_avx512_knights.inl"
170#include "simdlib_512_avx512_masks_knights.inl"
171#else // optimize for core
172#include "simdlib_512_avx512_core.inl"
173#include "simdlib_512_avx512_masks_core.inl"
174#endif // defined(SIMD_ARCH_KNIGHTS)
175#undef __SIMD_LIB_AVX512_HPP__
176        }; // struct AVX512ImplBase
177#endif     // #if SIMD_ARCH >= SIMD_ARCH_AVX512
178
179        struct Traits : SIMDImpl::Traits
180        {
181#if SIMD_ARCH == SIMD_ARCH_AVX
182            using IsaImpl = AVXImpl;
183#elif SIMD_ARCH == SIMD_ARCH_AVX2
184            using IsaImpl = AVX2Impl;
185#elif SIMD_ARCH == SIMD_ARCH_AVX512
186            using IsaImpl = AVX512Impl;
187#else
188#error Invalid value for SIMD_ARCH
189#endif
190
191            using Float   = SIMD512Impl::Float;
192            using Double  = SIMD512Impl::Double;
193            using Integer = SIMD512Impl::Integer;
194            using Vec4    = SIMD512Impl::Vec4;
195            using Mask    = SIMD512Impl::Mask;
196        };
197    } // namespace SIMD512Impl
198} // namespace SIMDImpl
199
200template <typename Traits>
201struct SIMDBase : Traits::IsaImpl
202{
203    using CompareType = typename Traits::CompareType;
204    using ScaleFactor = typename Traits::ScaleFactor;
205    using RoundMode   = typename Traits::RoundMode;
206    using SIMD        = typename Traits::IsaImpl;
207    using Float       = typename Traits::Float;
208    using Double      = typename Traits::Double;
209    using Integer     = typename Traits::Integer;
210    using Vec4        = typename Traits::Vec4;
211    using Mask        = typename Traits::Mask;
212}; // struct SIMDBase
213
214using SIMD128 = SIMDBase<SIMDImpl::SIMD128Impl::Traits>;
215using SIMD256 = SIMDBase<SIMDImpl::SIMD256Impl::Traits>;
216using SIMD512 = SIMDBase<SIMDImpl::SIMD512Impl::Traits>;
217
218template <typename SIMD_T>
219using CompareType = typename SIMD_T::CompareType;
220template <typename SIMD_T>
221using ScaleFactor = typename SIMD_T::ScaleFactor;
222template <typename SIMD_T>
223using RoundMode = typename SIMD_T::RoundMode;
224template <typename SIMD_T>
225using Float = typename SIMD_T::Float;
226template <typename SIMD_T>
227using Double = typename SIMD_T::Double;
228template <typename SIMD_T>
229using Integer = typename SIMD_T::Integer;
230template <typename SIMD_T>
231using Vec4 = typename SIMD_T::Vec4;
232template <typename SIMD_T>
233using Mask = typename SIMD_T::Mask;
234
235