AkSimdAvx.h 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458
  1. /*******************************************************************************
  2. The content of this file includes portions of the AUDIOKINETIC Wwise Technology
  3. released in source code form as part of the SDK installer package.
  4. Commercial License Usage
  5. Licensees holding valid commercial licenses to the AUDIOKINETIC Wwise Technology
  6. may use this file in accordance with the end user license agreement provided
  7. with the software or, alternatively, in accordance with the terms contained in a
  8. written agreement between you and Audiokinetic Inc.
  9. Apache License Usage
  10. Alternatively, this file may be used under the Apache License, Version 2.0 (the
  11. "Apache License"); you may not use this file except in compliance with the
  12. Apache License. You may obtain a copy of the Apache License at
  13. http://www.apache.org/licenses/LICENSE-2.0.
  14. Unless required by applicable law or agreed to in writing, software distributed
  15. under the Apache License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES
  16. OR CONDITIONS OF ANY KIND, either express or implied. See the Apache License for
  17. the specific language governing permissions and limitations under the License.
  18. Copyright (c) 2023 Audiokinetic Inc.
  19. *******************************************************************************/
  20. // AkSimdAvx.h
  21. /// \file
  22. /// AKSIMD - AVX implementation
  23. #ifndef _AK_SIMD_AVX_H_
  24. #define _AK_SIMD_AVX_H_
  25. #include <AK/SoundEngine/Common/AkTypes.h>
  26. #include <AK/SoundEngine/Platforms/SSE/AkSimd.h>
  27. #if defined(AKSIMD_AVX_SUPPORTED)
  28. #include <immintrin.h>
  29. ////////////////////////////////////////////////////////////////////////
  30. /// @name AKSIMD types
  31. //@{
  32. typedef float AKSIMD_F32; ///< 32-bit float
  33. typedef __m256 AKSIMD_V8F32; ///< Vector of 8 32-bit floats
  34. typedef __m256d AKSIMD_V4F64; ///< Vector of 4 64-bit floats
  35. typedef __m256i AKSIMD_V8I32; ///< Vector of 8 32-bit signed integers
  36. typedef AKSIMD_V8F32 AKSIMD_V8COND; ///< Vector of 8 comparison results
  37. typedef AKSIMD_V8F32 AKSIMD_V8FCOND; ///< Vector of 8 comparison results
  38. typedef AKSIMD_V8I32 AKSIMD_V8ICOND;
  39. //@}
  40. ////////////////////////////////////////////////////////////////////////
  41. ////////////////////////////////////////////////////////////////////////
  42. /// @name AKSIMD loading / setting
  43. //@{
  44. /// Loads eight single-precision floating-point values from memory.
  45. /// The address does not need to be 32-byte aligned (see _mm_loadu_ps).
  46. /// On every modern x86 processor this performs the same as an aligned load.
  47. #define AKSIMD_LOAD_V8F32( __addr__ ) _mm256_loadu_ps( (AkReal32*)(__addr__) )
  48. /// Loads a single single-precision, floating-point value, copying it into
  49. /// all eight words (see _mm_load1_ps, _mm_load_ps1)
  50. #define AKSIMD_LOAD1_V8F32( __scalar__ ) _mm256_broadcast_ss( &(__scalar__) )
  51. /// Loads a single double-precision, floating-point value, and copies it into
  52. /// all elements of the vector (see _mm_load_pd1)
  53. #define AKSIMD_LOAD1_V4F64( __scalar__ ) _mm256_castpd_ps(_mm256_broadcast_sd( &(__scalar__) ))
  54. /// Sets the eight single-precision, floating-point values to in_value (see
  55. /// _mm_set1_ps, _mm_set_ps1)
  56. #define AKSIMD_SET_V8F32( __scalar__ ) _mm256_set1_ps( (__scalar__) )
  57. /// Populates the full vector with the 8 floating point values provided
  58. #define AKSIMD_SETV_V8F32( _h, _g, _f, _e, _d, _c, _b, _a ) _mm256_set_ps( (_h), (_g), (_f), (_e), (_d), (_c), (_b), (_a) )
  59. /// Populates the full vector with the 4 double-prec floating point values provided
  60. #define AKSIMD_SETV_V4F64( _d, _c, _b, _a ) _mm256_castpd_ps( _mm256_set_pd( (_d), (_c), (_b), (_a) ) )
  61. /// Sets the eight single-precision, floating-point values to zero (see
  62. /// _mm_setzero_ps)
  63. #define AKSIMD_SETZERO_V8F32() _mm256_setzero_ps()
  64. /// Loads a single-precision, floating-point value into the low word
  65. /// and clears the upper seven words.
  66. /// r0 := *p; r1...r7 := 0.0 (see _mm_load_ss)
  67. #define AKSIMD_LOAD_SS_V8F32( __addr__ ) _mm256_zextps128_ps256(_mm_load_ss( (__addr__) ))
  68. /// Loads the two m128i's provided into the output m256i a
  69. /// Note that this should be utilized instead of, e.g. adding & utilizing a macro "AKSIMD_INSERT_V8I32(m, i, idx)"
  70. /// Because there is no direct corresponding instruction for an insert into 256. You should load into 128s
  71. /// and use that. Some compilers do not handle _mm256_insert_epi32 (etc) well, or even include them
  72. #define AKSIMD_SETV_V2F128( m2, m1) _mm256_set_m128(m2, m1)
  73. #define AKSIMD_INSERT_V2F128( a, m128, idx) _mm256_insertf128_ps(a, m128, idx)
  74. #define AKSIMD_GETELEMENT_V8F32( __vName, __num__ ) ((AkReal32*)&(__vName))[(__num__)]
  75. #define AKSIMD_GETELEMENT_V4F64( __vName, __num__ ) ((AkReal64*)&(__vName))[(__num__)]
  76. #define AKSIMD_GETELEMENT_V8I32( __vName, __num__ ) ((AkInt32*)&(__vName))[(__num__)]
  77. #define AKSIMD_GETELEMENT_V4I64( __vName, __num__ ) ((AkInt64*)&(__vName))[(__num__)]
  78. //@}
  79. ////////////////////////////////////////////////////////////////////////
  80. ////////////////////////////////////////////////////////////////////////
  81. /// @name AKSIMD storing
  82. //@{
  83. /// Stores eight single-precision, floating-point values.
  84. /// The address does not need to be 32-byte aligned (see _mm_storeu_ps).
  85. /// On every modern x86 processor this performs the same as an aligned store.
  86. #define AKSIMD_STORE_V8F32( __addr__, __vec__ ) _mm256_storeu_ps( (AkReal32*)(__addr__), (__vec__) )
  87. /// Stores the lower single-precision, floating-point value.
  88. /// *p := a0 (see _mm_store_ss)
  89. #define AKSIMD_STORE1_V8F32( __addr__, __vec__ ) _mm_store_ss( (AkReal32*)(__addr__), _mm256_castps256_ps128( (__vec__) ) )
  90. //@}
  91. ////////////////////////////////////////////////////////////////////////
  92. ////////////////////////////////////////////////////////////////////////
  93. /// @name AKSIMD shuffling
  94. //@{
  95. /// Selects eight specific single-precision, floating-point values from
  96. /// a and b, based on the mask i within 128-bit lanes (see _mm256_shuffle_ps)
  97. /// This means that the AKSIMD_SHUFFLE operand still picks 1 of 4 32b components
  98. /// inside of each of the 2 128b lanes.
  99. // Usage: AKSIMD_SHUFFLE_V8F32( vec1, vec2, AKSIMD_SHUFFLE( z, y, x, w ) )
  100. #define AKSIMD_SHUFFLE_V8F32( a, b, i ) _mm256_shuffle_ps( a, b, i )
  101. /// For each 128b lane, Swap the 2 lower floats together and the 2 higher floats together. ( h g f e d c b a -> g h e f c d a b )
  102. #define AKSIMD_SHUFFLE_V8_BADC( __a__ ) AKSIMD_SHUFFLE_V8F32( (__a__), (__a__), AKSIMD_SHUFFLE(2,3,0,1))
  103. /// For each 128b lane, Swap the 2 lower floats with the 2 higher floats. ( h g f e d c b a -> f e h g b a d c )
  104. #define AKSIMD_SHUFFLE_V8_CDAB( __a__ ) AKSIMD_SHUFFLE_V8F32( (__a__), (__a__), AKSIMD_SHUFFLE(1,0,3,2))
  105. /// For each 128b lane, barrel-shift all floats by one. ( h g f e d c b a -> e h g f a d c b )
  106. #define AKSIMD_SHUFFLE_V8_BCDA( __a__ ) AKSIMD_SHUFFLE_V8F32( (__a__), (__a__), AKSIMD_SHUFFLE(0,3,2,1))
  107. /// For each 128b lane, duplicates the odd items into the even items ( h g f e d c b a -> h h f f d d b b )
  108. #define AKSIMD_DUP_V8_ODD(__vv) AKSIMD_SHUFFLE_V8F32(__vv, __vv, AKSIMD_SHUFFLE(3,3,1,1))
  109. /// For each 128b lane, duplicates the even items into the odd items ( h g f e d c b a -> g g e e c c a a )
  110. #define AKSIMD_DUP_V8_EVEN(__vv) AKSIMD_SHUFFLE_V8F32(__vv, __vv, AKSIMD_SHUFFLE(2,2,0,0))
  111. /// Shuffle 32-bit integers in a within 128-bit lanes using the control in i, and return the results
  112. #define AKSIMD_SHUFFLE_V8I32( a, b, i ) _mm256_castps_si256(_mm256_shuffle_ps( _mm256_castsi256_ps(a), _mm256_castsi256_ps(b), i ))
  113. /// single-precision (32-bit) floating-point elements in a within 128-bit lanes using the control in b, and store the results in dst.
  114. #define AKSIMD_PERMUTEVAR_V8F32(a, b) _mm256_permutevar_ps(a, b)
  115. // Macro for selection parameter for AKSIMD_PERMUTE_2X128_V8F32()
  116. #define AKSIMD_PERMUTE128( l1, l0 ) (((l1) << 4) | (l0))
  117. /// For each 128b lane, select one of the four input 128b lanes across a and b,
  118. /// based on the mask i. AKSIMD_SHUFFLE can still be directly used as a control
  119. #define AKSIMD_PERMUTE_2X128_V8F32( a, b, i ) _mm256_permute2f128_ps(a, b, i)
  120. /// Selects the lower of each of the 128b lanes in a and b to be the result ( B A ), ( D C ) -> ( C A )
  121. #define AKSIMD_DEINTERLEAVELANES_LO_V8F32( a, b ) AKSIMD_PERMUTE_2X128_V8F32(a, b, AKSIMD_PERMUTE128(2, 0))
  122. /// Selects the higher of each of the 128b lanes in a and b to be the result ( B A ), ( D C) -> ( D B )
  123. #define AKSIMD_DEINTERLEAVELANES_HI_V8F32( a, b ) AKSIMD_PERMUTE_2X128_V8F32(a, b, AKSIMD_PERMUTE128(3, 1))
  124. /// Gets the specified 128b lane from a and stores it in the result
  125. #define AKSIMD_EXTRACT_V2F128( a, i ) _mm256_extractf128_ps(a, i)
  126. /// Rotate the 4x4 vectors in each of the 128b lanes. After rotation:
  127. /// A[7:0] = D[4] C[4] B[4] A[4] D[0] C[0] B[0] A[0]
  128. /// B[7:0] = D[5] C[5] B[5] A[5] D[1] C[1] B[1] A[1]
  129. /// C[7:0] = D[6] C[6] B[6] A[6] D[2] C[2] B[2] A[2]
  130. /// D[7:0] = D[7] C[7] B[7] A[7] D[3] C[3] B[3] A[3]
  131. AkForceInline void AKSIMD_TRANSPOSE8X4_V8F32(AKSIMD_V8F32& A, AKSIMD_V8F32& B, AKSIMD_V8F32& C, AKSIMD_V8F32& D)
  132. {
  133. AKSIMD_V8F32 tmp1, tmp2, tmp3, tmp4;
  134. tmp1 = AKSIMD_SHUFFLE_V8F32(A, B, AKSIMD_SHUFFLE(1,0,1,0));
  135. tmp2 = AKSIMD_SHUFFLE_V8F32(A, B, AKSIMD_SHUFFLE(3,2,3,2));
  136. tmp3 = AKSIMD_SHUFFLE_V8F32(C, D, AKSIMD_SHUFFLE(1,0,1,0));
  137. tmp4 = AKSIMD_SHUFFLE_V8F32(C, D, AKSIMD_SHUFFLE(3,2,3,2));
  138. A = AKSIMD_SHUFFLE_V8F32(tmp1, tmp3, AKSIMD_SHUFFLE(2, 0, 2, 0));
  139. B = AKSIMD_SHUFFLE_V8F32(tmp1, tmp3, AKSIMD_SHUFFLE(3, 1, 3, 1));
  140. C = AKSIMD_SHUFFLE_V8F32(tmp2, tmp4, AKSIMD_SHUFFLE(2, 0, 2, 0));
  141. D = AKSIMD_SHUFFLE_V8F32(tmp2, tmp4, AKSIMD_SHUFFLE(3, 1, 3, 1));
  142. }
  143. //@}
  144. ////////////////////////////////////////////////////////////////////////
  145. ////////////////////////////////////////////////////////////////////////
  146. /// @name AKSIMD arithmetic
  147. //@{
  148. /// Subtracts the eight single-precision, floating-point values of
  149. /// a and b (a - b) (see _mm_sub_ps)
  150. #define AKSIMD_SUB_V8F32( a, b ) _mm256_sub_ps( a, b )
  151. /// Subtracts the lower single-precision, floating-point values of a and b.
  152. /// The upper three single-precision, floating-point values are passed through from a.
  153. /// r0 := a0 - b0 ; r1...r7 := a1...a7 (see _mm_sub_ss)
  154. #define AKSIMD_SUB_SS_V8F32( a, b ) _mm256_sub_ps( a, _mm256_and_ps(b, _mm256_setr_epi32( -1, 0, 0, 0, 0, 0, 0, 0 ) ) )
  155. /// Adds the eight single-precision, floating-point values of
  156. /// a and b (see _mm_add_ps)
  157. #define AKSIMD_ADD_V8F32( a, b ) _mm256_add_ps( a, b )
  158. /// Performs alternatiing subs and adds of the eight single-precision,
  159. /// floating-point values of a and b (see _mm_addsub_ps)
  160. #define AKSIMD_ADDSUB_V8F32( a, b ) _mm256_addsub_ps( a, b )
  161. /// Adds the lower single-precision, floating-point values of a and b; the
  162. /// upper three single-precision, floating-point values are passed through from a.
  163. /// r0 := a0 + b0; r1...r7 := a1...a7 (see _mm_add_ss)
  164. #define AKSIMD_ADD_SS_V8F32( a, b ) _mm256_add_ps( a, _mm256_and_ps(b, _mm256_setr_epi32( -1, 0, 0, 0, 0, 0, 0, 0 ) ) )
  165. /// Multiplies the eight single-precision, floating-point values
  166. /// of a and b (see _mm_mul_ps)
  167. #define AKSIMD_MUL_V8F32( a, b ) _mm256_mul_ps( a, b )
  168. #define AKSIMD_DIV_V8F32( a, b ) _mm256_div_ps( a, b )
  169. /// Multiplies the lower single-precision, floating-point values of
  170. /// a and b; the upper three single-precision, floating-point values
  171. /// are passed through from a.
  172. /// r0 := a0 * b0; r1...r7 := a1...a7 (see _mm_mul_ss)
  173. #define AKSIMD_MUL_SS_V8F32( a, b ) _mm256_mul_ps( a, _mm256_blend_ps(b, _mm256_set1_ps(1.0f), 0xfe ) )
  174. /// Computes the minima of the eight single-precision, floating-point
  175. /// values of a and b (see _mm_min_ps)
  176. #define AKSIMD_MIN_V8F32( a, b ) _mm256_min_ps( a, b )
  177. /// Computes the maximums of the eight single-precision, floating-point
  178. /// values of a and b (see _mm_max_ps)
  179. #define AKSIMD_MAX_V8F32( a, b ) _mm256_max_ps( a, b )
  180. /// Computes the absolute value
  181. #define AKSIMD_ABS_V8F32( a ) _mm256_andnot_ps(_mm256_set1_ps(-0.f), a)
  182. /// Changes the sign
  183. #define AKSIMD_NEG_V8F32( __a__ ) _mm256_xor_ps(_mm256_set1_ps(-0.f), __a__)
  184. /// Vector square root aproximation (see _mm_sqrt_ps)
  185. #define AKSIMD_SQRT_V8F32( __a__ ) _mm256_sqrt_ps( (__a__) )
  186. /// Vector reciprocal square root approximation 1/sqrt(a), or equivalently, sqrt(1/a)
  187. #define AKSIMD_RSQRT_V8F32( __a__ ) _mm256_rsqrt_ps( (__a__) )
  188. /// Vector reciprocal
  189. #define AKSIMD_RECIP_V8F32( __a__ ) _mm256_rcp_ps( (__a__) )
  190. /// Vector ceil
  191. #define AKSIMD_CEIL_V8F32( __a__ ) _mm256_ceil_ps( (__a__) )
  192. #define AKSIMD_XOR_V8F32( a, b ) _mm256_xor_ps(a,b)
  193. #define AKSIMD_OR_V8F32( a, b ) _mm256_or_ps(a,b)
  194. #define AKSIMD_AND_V8F32( a, b) _mm256_and_ps(a,b)
  195. #define AKSIMD_NOT_V8F32( a ) _mm256_xor_ps(a,_mm256_castsi256_ps(_mm256_set1_epi32(~0)))
  196. #define AKSIMD_ANDNOT_V8F32( a, b ) _mm256_andnot_ps(a, b)
  197. /// horizontal add across the entire vector - vVec will be updated to contain the sum of every input element of vVec
  198. /// \akwarning
  199. /// Don't expect this to be very efficient.
  200. /// \endakwarning
  201. static AkForceInline AKSIMD_V8F32 AKSIMD_HORIZONTALADD_V8F32(AKSIMD_V8F32 vVec)
  202. {
  203. __m256 vAb = _mm256_shuffle_ps(vVec, vVec, 0xB1);
  204. __m256 vHaddAb = _mm256_add_ps(vVec, vAb);
  205. __m256 vHaddCd = _mm256_shuffle_ps(vHaddAb, vHaddAb, 0x4E);
  206. __m256 vHaddAbcd = _mm256_add_ps(vHaddAb, vHaddCd);
  207. __m256 vHaddEfgh = _mm256_permute2f128_ps(vHaddAbcd, vHaddAbcd, 0x01);
  208. __m256 vHaddAll = _mm256_add_ps(vHaddAbcd, vHaddEfgh);
  209. return vHaddAll;
  210. }
  211. /// Cross-platform SIMD multiplication of 8 complex data elements with interleaved real and imaginary parts
  212. static AkForceInline AKSIMD_V8F32 AKSIMD_COMPLEXMUL_V8F32(const AKSIMD_V8F32 cIn1, const AKSIMD_V8F32 cIn2)
  213. {
  214. __m256 real1Ext = _mm256_moveldup_ps(cIn1); // reals extended (a3, a3, a2, a2, a1, a1, a0, a0)
  215. __m256 in2Shuf = _mm256_shuffle_ps(cIn2, cIn2, 0xB1); // shuf multiplicand (c3, d3, c2, d2, c1, d1, c0, d0)
  216. __m256 imag1Ext = _mm256_movehdup_ps(cIn1); // multiplier imag (b3, b3, b2, b2, b1, b1, b0, b0)
  217. __m256 temp = _mm256_mul_ps(imag1Ext, in2Shuf); // temp (b3c3, b3d3, b2c2, b2d2, b1c1, b1d1, b0c0, b0d0)
  218. __m256 mul = _mm256_mul_ps(real1Ext, cIn2); // (a3d3, a3c3, a2d2, a2c2, a1d1, a1c1, a0d0, a0c0)
  219. __m256 out = _mm256_addsub_ps(mul, temp); // final (a3d3+b3c3, a3c3-b3d3, a2d2+b2c2, a2c2-b2d2, a1d1+b1c1, a1c1-b1d1, a0d0+b0c0, a0c0-b0d0)
  220. return out;
  221. }
  222. //@}
  223. ////////////////////////////////////////////////////////////////////////
  224. ////////////////////////////////////////////////////////////////////////
  225. /// @name AKSIMD packing / unpacking
  226. //@{
  227. /// Selects and interleaves the lower two single-precision, floating-point
  228. /// values from each 128-bit lane in a and b (see _mm_unpacklo_ps)
  229. /// i.e. r0 := a0, r1 := b0, r2 := a1, r3 := b1, r4 := a4, r5 := b4, r6 := a5, r7 := b5
  230. #define AKSIMD_UNPACKLO_V8F32( a, b ) _mm256_unpacklo_ps( a, b )
  231. /// Selects and interleaves the upper two single-precision, floating-point
  232. /// values from each 128-bit lane a and b (see _mm_unpackhi_ps)
  233. /// i.e. r0 := a2, r1 := b2, r2 := a3, r3 := b3, r4 := a6, r5 := b6, r6 := a7, r7 := b7
  234. #define AKSIMD_UNPACKHI_V8F32( a, b ) _mm256_unpackhi_ps( a, b )
  235. //@}
  236. ////////////////////////////////////////////////////////////////////////
  237. ////////////////////////////////////////////////////////////////////////
  238. /// @name AKSIMD vector comparison
  239. //@{
  240. #define AKSIMD_CMP_CTRLMASKV8 __m256
  241. /// Vector "<=" operation (see _mm_cmple_ps)
  242. #define AKSIMD_LTEQ_V8F32( __a__, __b__ ) _mm256_cmp_ps( (__a__), (__b__), _CMP_LE_OS )
  243. #define AKSIMD_LT_V8F32( __a__, __b__ ) _mm256_cmp_ps( (__a__), (__b__), _CMP_LT_OS )
  244. /// Vector ">=" operation (see _mm_cmple_ps)
  245. #define AKSIMD_GTEQ_V8F32( __a__, __b__ ) _mm256_cmp_ps( (__a__), (__b__), _CMP_GE_OS )
  246. #define AKSIMD_GT_V8F32( __a__, __b__ ) _mm256_cmp_ps( (__a__), (__b__), _CMP_GT_OS )
  247. /// Vector "==" operation (see _mm_cmpeq_ps)
  248. #define AKSIMD_EQ_V8F32( __a__, __b__ ) _mm256_cmp_ps( (__a__), (__b__), _CMP_EQ_OS )
  249. /// Return a when control mask is 0, return b when control mask is non zero, control mask is in c and usually provided by above comparison operations
  250. static AkForceInline AKSIMD_V8F32 AKSIMD_VSEL_V8F32( AKSIMD_V8F32 vA, AKSIMD_V8F32 vB, AKSIMD_V8F32 vMask )
  251. {
  252. return _mm256_blendv_ps(vA, vB, vMask);
  253. }
  254. // (cond1 >= cond2) ? b : a.
  255. #define AKSIMD_SEL_GTEQ_V8F32( __a__, __b__, __cond1__, __cond2__ ) AKSIMD_VSEL_V8F32( __a__, __b__, AKSIMD_GTEQ_V8F32( __cond1__, __cond2__ ) )
  256. // a >= 0 ? b : c ... Written, like, you know, the normal C++ operator syntax.
  257. #define AKSIMD_SEL_GTEZ_V8F32( __a__, __b__, __c__ ) AKSIMD_VSEL_V8F32( (__c__), (__b__), AKSIMD_GTEQ_V8F32( __a__, _mm256_set1_ps(0) ) )
  258. #define AKSIMD_SPLAT_V8F32(var, idx) AKSIMD_SHUFFLE_V8F32(var,var, AKSIMD_SHUFFLE(idx,idx,idx,idx))
  259. #define AKSIMD_MASK_V8F32( __a__ ) _mm256_movemask_ps( __a__ )
  260. // returns true if every element of the provided vector is zero
  261. #define AKSIMD_TESTZERO_V8I32( __a__ ) (_mm256_testz_si256(__a__,__a__) != 0)
  262. #define AKSIMD_TESTZERO_V8F32( __a__) AKSIMD_TESTZERO_V8I32(_mm256_castps_si256(__a__))
  263. // returns true if every element of the provided vector is one
  264. #define AKSIMD_TESTONES_V8I32(__a__) (_mm256_testc_si256(__a__, _mm256_set1_epi32(~0)) != 0)
  265. #define AKSIMD_TESTONES_V8F32( __a__) AKSIMD_TESTONES_V8I32(_mm256_castps_si256(__a__))
  266. //@}
  267. ////////////////////////////////////////////////////////////////////////
  268. /// Loads 256-bit value (see _mm_loadu_si128)
  269. /// On every modern x86 processor this performs the same as an aligned load.
  270. #define AKSIMD_LOAD_V8I32( __addr__ ) _mm256_loadu_si256( (__addr__) )
  271. /// Sets the eight 32-bit integer values to zero (see _mm_setzero_si128)
  272. #define AKSIMD_SETZERO_V8I32() _mm256_setzero_si256()
  273. /// Sets the provided scalar value at the first index of the vector, and zeroes everything else
  274. #define AKSIMD_SET_V8I32( __scalar__ ) _mm256_set1_epi32( (__scalar__) )
  275. /// Populates the full vector with the 8 values provided
  276. #define AKSIMD_SETV_V8I32( _h, _g, _f, _e, _d, _c, _b, _a ) _mm256_set_epi32( (_h), (_g), (_f), (_e), (_d), (_c), (_b), (_a) )
  277. /// Loads the two m128i's provided into the output m256i a
  278. /// Note that this should be utilized instead of, e.g. adding & utilizing a macro "AKSIMD_INSERT_V8I32(m, i, idx)"
  279. /// Because there is no direct corresponding instruction for an insert into 256. You should load into 128s
  280. /// and use that. Some compilers do not handle _mm256_insert_epi32 (etc) well, or even include them
  281. #define AKSIMD_SET_V2I128(m1, m2) _mm256_setr_m128i(m1, m2)
  282. /// Stores eight 32-bit integer values.
  283. /// The address does not need to be 32-byte aligned (see _mm_storeu_si128).
  284. /// On every modern x86 processor this performs the same as an aligned load.
  285. #define AKSIMD_STORE_V8I32( __addr__, __vec__ ) _mm256_storeu_si256( (__addr__), (__vec__) )
  286. ////////////////////////////////////////////////////////////////////////
  287. /// @name AKSIMD conversion
  288. //@{
  289. /// Converts the eight signed 32-bit integer values of a to single-precision,
  290. /// floating-point values (see _mm_cvtepi32_ps)
  291. #define AKSIMD_CONVERT_V8I32_TO_V8F32( __vec__ ) _mm256_cvtepi32_ps( (__vec__) )
  292. /// Converts the eight single-precision, floating-point values of a to signed
  293. /// 32-bit integer values by rounding (see _mm_cvtps_epi32)
  294. #define AKSIMD_ROUND_V8F32_TO_V8I32( __vec__ ) _mm256_cvtps_epi32( (__vec__) )
  295. /// Converts the eight single-precision, floating-point values of a to signed
  296. /// 32-bit integer values by truncating (see _mm_cvttps_epi32)
  297. #define AKSIMD_TRUNCATE_V8F32_TO_V8I32( __vec__ ) _mm256_cvttps_epi32( (__vec__) )
  298. /// Converts the eight half-precision floating-point values of vec to
  299. /// eight full-precision floating-point values
  300. /// WARNING: Using this requires F16C support, which is not guaranteed on AVX
  301. #define AKSIMD_CONVERT_V8F16_TO_V8F32( __vec__ ) _mm256_cvtph_ps( (__vec__) )
  302. /// Converts the eight single-precision, floating-point values of vec to
  303. /// eight half-precision floating-point values
  304. /// WARNING: Using this requires F16C support, which is not guaranteed on AVX
  305. #define AKSIMD_CONVERT_V8F32_TO_V8F16( __vec__ ) _mm256_cvtps_ph(__vec__, (_MM_FROUND_TO_NEAREST_INT ) )
  306. //@}
  307. ////////////////////////////////////////////////////////////////////////
  308. ////////////////////////////////////////////////////////////////////////
  309. /// @name AKSIMD cast
  310. //@{
  311. /// Cast vector of type AKSIMD_V4F64 to type AKSIMD_V8F32. This intrinsic is only
  312. /// used for compilation and does not generate any instructions, thus it has zero latency.
  313. #define AKSIMD_CAST_V4F64_TO_V8F32( __vec__ ) _mm256_castpd_ps(__vec__)
  314. /// Cast vector of type AKSIMD_V4F64 to type AKSIMD_V8I32. This intrinsic is only
  315. /// used for compilation and does not generate any instructions, thus it has zero latency.
  316. #define AKSIMD_CAST_V4F64_TO_V8I32( __vec__ ) _mm256_castpd_si256(__vec__)
  317. /// Cast vector of type AKSIMD_V8F32 to type AKSIMD_V4F64. This intrinsic is only
  318. /// used for compilation and does not generate any instructions, thus it has zero latency.
  319. #define AKSIMD_CAST_V8F32_TO_V4F64( __vec__ ) _mm256_castps_pd(__vec__)
  320. /// Cast vector of type AKSIMD_V8F32 to type AKSIMD_V8I32. This intrinsic is only
  321. /// used for compilation and does not generate any instructions, thus it has zero latency.
  322. #define AKSIMD_CAST_V8F32_TO_V8I32( __vec__ ) _mm256_castps_si256(__vec__)
  323. /// Cast vector of type AKSIMD_V8I32 to type AKSIMD_V4F64. This intrinsic is only
  324. /// used for compilation and does not generate any instructions, thus it has zero latency.
  325. #define AKSIMD_CAST_V8I32_TO_V4F64( __vec__ ) _mm256_castsi256_pd(__vec__)
  326. /// Cast vector of type AKSIMD_V8I32 to type AKSIMD_V8F32. This intrinsic is only
  327. /// used for compilation and does not generate any instructions, thus it has zero latency.
  328. #define AKSIMD_CAST_V8I32_TO_V8F32( __vec__ ) _mm256_castsi256_ps(__vec__)
  329. /// Cast vector of type AKSIMD_V8COND to AKSIMD_V8F32.
  330. #define AKSIMD_CAST_V8COND_TO_V8F32( __vec__ ) (__vec__)
  331. /// Cast vector of type AKSIMD_V8F32 to AKSIMD_V8COND.
  332. #define AKSIMD_CAST_V8F32_TO_V8COND( __vec__ ) (__vec__)
  333. /// Cast vector of type AKSIMD_V8COND to AKSIMD_V8I32.
  334. #define AKSIMD_CAST_V8COND_TO_V8I32( __vec__ ) _mm256_castps_si256(__vec__)
  335. /// Cast vector of type AKSIMD_V8I32 to AKSIMD_V8COND.
  336. #define AKSIMD_CAST_V8I32_TO_V8COND( __vec__ ) _mm256_castsi256_ps(__vec__)
  337. //@}
  338. ////////////////////////////////////////////////////////////////////////
  339. #endif //_AK_SIMD_AVX_H_
  340. #endif