rsimd

Make SIMD instruction sets easier to use
git clone git://git.meso-star.fr/rsimd.git
Log | Files | Refs | README | LICENSE

ssef.h (11789B)


      1 /* Copyright (C) 2014-2019, 2021, 2023, 2025 Vincent Forest (vaplv@free.fr)
      2  *
      3  * The RSIMD library is free software: you can redistribute it and/or modify
      4  * it under the terms of the GNU General Public License as published
      5  * by the Free Software Foundation, either version 3 of the License, or
      6  * (at your option) any later version.
      7  *
      8  * The RSIMD library is distributed in the hope that it will be useful,
      9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
     11  * GNU General Public License for more details.
     12  *
     13  * You should have received a copy of the GNU General Public License
     14  * along with the RSIMD library. If not, see <http://www.gnu.org/licenses/>. */
     15 
     16 #ifndef RSIMD_SSEF_H
     17 #define RSIMD_SSEF_H
     18 
     19 /*
     20  * 4 packed single precision floating-point values
     21  */
     22 
     23 #include "sse_swz.h"
     24 
     25 #include <rsys/math.h>
     26 #include <xmmintrin.h>
     27 #include <emmintrin.h>
     28 #ifdef SIMD_SSE4_1
     29   #include <smmintrin.h>
     30 #endif
     31 #ifdef FMADD
     32   #include <immintrin.h>
     33 #endif
     34 
     35 typedef __m128 v4f_T;
     36 #define V4F_AT__(Vec, Id) __builtin_ia32_vec_ext_v4sf(Vec, Id)
     37 
     38 #define v4f_SWZ__(Vec, Op0, Op1, Op2, Op3)                                     \
     39   _mm_shuffle_ps(vec, vec, _MM_SHUFFLE(Op3, Op2, Op1, Op0))
     40 GENERATE_V4_SWZ_FUNCS__(v4f) /* Swizzle operations */
     41 
     42 /*******************************************************************************
     43  * Set operations
     44  ******************************************************************************/
     45 static FINLINE float*
     46 v4f_store(float dst[4], v4f_T v)
     47 {
     48   ASSERT(dst && IS_ALIGNED(dst, 16));
     49   _mm_store_ps(dst, v);
     50   return dst;
     51 }
     52 
     53 static FINLINE v4f_T
     54 v4f_load(const float src[4])
     55 {
     56   ASSERT(src && IS_ALIGNED(src, 16));
     57   return _mm_load_ps(src);
     58 }
     59 
     60 static FINLINE v4f_T
     61 v4f_loadu(const float src[4])
     62 {
     63   ASSERT(src);
     64   return _mm_set_ps(src[3], src[2], src[1], src[0]);
     65 }
     66 
     67 static FINLINE v4f_T
     68 v4f_loadu3(const float src[3])
     69 {
     70   ASSERT(src);
     71   return _mm_set_ps(0.f, src[2], src[1], src[0]);
     72 }
     73 
     74 static FINLINE v4f_T
     75 v4f_set1(const float x)
     76 {
     77   return _mm_set1_ps(x);
     78 }
     79 
     80 static FINLINE v4f_T
     81 v4f_set(const float x, const float y, const float z, const float w)
     82 {
     83   return _mm_set_ps(w, z, y, x);
     84 }
     85 
     86 static FINLINE v4f_T
     87 v4f_zero(void)
     88 {
     89   return _mm_setzero_ps();
     90 }
     91 
     92 static FINLINE v4f_T
     93 v4f_mask(const int32_t x, const int32_t y, const int32_t z, const int32_t w)
     94 {
     95   return _mm_castsi128_ps(_mm_set_epi32(w, z, y, x));
     96 }
     97 
     98 static FINLINE v4f_T
     99 v4f_mask1(const int32_t x)
    100 {
    101   return _mm_castsi128_ps(_mm_set1_epi32(x));
    102 }
    103 
    104 static FINLINE v4f_T
    105 v4f_true(void)
    106 {
    107   return _mm_castsi128_ps(_mm_set1_epi32(~0));
    108 }
    109 
    110 static FINLINE v4f_T
    111 v4f_false(void)
    112 {
    113   return v4f_zero();
    114 }
    115 
    116 /*******************************************************************************
    117  * Extract components
    118  ******************************************************************************/
    119 static FINLINE float v4f_x(const v4f_T v) { return V4F_AT__(v, 0); }
    120 static FINLINE float v4f_y(const v4f_T v) { return V4F_AT__(v, 1); }
    121 static FINLINE float v4f_z(const v4f_T v) { return V4F_AT__(v, 2); }
    122 static FINLINE float v4f_w(const v4f_T v) { return V4F_AT__(v, 3); }
    123 
    124 static FINLINE int32_t
    125 v4f_mask_x(const v4f_T v)
    126 {
    127   union { float f; int32_t i; } ucast;
    128   ucast.f = v4f_x(v);
    129   return ucast.i;
    130 }
    131 
    132 static FINLINE int32_t
    133 v4f_mask_y(const v4f_T v)
    134 {
    135   union { float f; int32_t i; } ucast;
    136   ucast.f = v4f_y(v);
    137   return ucast.i;
    138 }
    139 
    140 static FINLINE int32_t
    141 v4f_mask_z(const v4f_T v)
    142 {
    143   union { float f; int32_t i; } ucast;
    144   ucast.f = v4f_z(v);
    145   return ucast.i;
    146 }
    147 
    148 static FINLINE int32_t
    149 v4f_mask_w(const v4f_T v)
    150 {
    151   union { float f; int32_t i; } ucast;
    152   ucast.f = v4f_w(v);
    153   return ucast.i;
    154 }
    155 
    156 static FINLINE int
    157 v4f_movemask(const v4f_T v)
    158 {
    159   return _mm_movemask_ps(v);
    160 }
    161 
    162 /*******************************************************************************
    163  * Merge operations
    164  ******************************************************************************/
    165 static FINLINE v4f_T
    166 v4f_xayb(const v4f_T xyzw, const v4f_T abcd)
    167 {
    168   return _mm_unpacklo_ps(xyzw, abcd);
    169 }
    170 
    171 static FINLINE v4f_T
    172 v4f_xyab(const v4f_T xyzw, const v4f_T abcd)
    173 {
    174   return _mm_movelh_ps(xyzw, abcd);
    175 }
    176 
    177 static FINLINE v4f_T
    178 v4f_zcwd(const v4f_T xyzw, const v4f_T abcd)
    179 {
    180   return _mm_unpackhi_ps(xyzw, abcd);
    181 }
    182 
    183 static FINLINE v4f_T
    184 v4f_zwcd(const v4f_T xyzw, const v4f_T abcd)
    185 {
    186   return _mm_movehl_ps(abcd, xyzw);
    187 }
    188 
    189 static FINLINE v4f_T
    190 v4f_ayzw(const v4f_T xyzw, const v4f_T abcd)
    191 {
    192   return _mm_move_ss(xyzw, abcd);
    193 }
    194 
    195 static FINLINE v4f_T
    196 v4f_xycd(const v4f_T xyzw, const v4f_T abcd)
    197 {
    198   return _mm_shuffle_ps(xyzw, abcd, _MM_SHUFFLE(3, 2, 1, 0));
    199 }
    200 
    201 static FINLINE v4f_T
    202 v4f_ywbd(const v4f_T xyzw, const v4f_T abcd)
    203 {
    204   return _mm_shuffle_ps(xyzw, abcd, _MM_SHUFFLE(3, 1, 3, 1));
    205 }
    206 
    207 static FINLINE v4f_T
    208 v4f_xbzw(const v4f_T xyzw, const v4f_T abcd)
    209 {
    210   const v4f_T zwzw = _mm_movehl_ps(xyzw, xyzw);
    211   const v4f_T abzw = _mm_movelh_ps(abcd, zwzw);
    212   return _mm_move_ss(abzw, xyzw);
    213 }
    214 
    215 static FINLINE v4f_T
    216 v4f_xycw(const v4f_T xyzw, const v4f_T abcd)
    217 {
    218 #if 0 /* SSE3 */
    219   const v4f_T yyww = _mm_movehdup_ps(xyzw);
    220 #else
    221   const v4f_T yyww = v4f_yyww(xyzw);
    222 #endif
    223   const v4f_T cwdw = _mm_unpackhi_ps(abcd, yyww);
    224   return _mm_movelh_ps(xyzw, cwdw);
    225 }
    226 
    227 static FINLINE v4f_T
    228 v4f_xyzd(const v4f_T xyzw, const v4f_T abcd)
    229 {
    230 #if 0 /* SSE3 */
    231   const v4f_T bbdd = _mm_movehdup_ps(abcd);
    232 #else
    233   const v4f_T bbdd = v4f_yyww(abcd);
    234 #endif
    235   const v4f_T zdwd = _mm_unpackhi_ps(xyzw, bbdd);
    236   return _mm_movelh_ps(xyzw, zdwd);
    237 }
    238 
    239 static FINLINE v4f_T
    240 v4f_048C
    241   (const v4f_T v0123, const v4f_T v4567, const v4f_T v89AB, const v4f_T vCDEF)
    242 {
    243   const v4f_T v0415 = v4f_xayb(v0123, v4567);
    244   const v4f_T v8C9D = v4f_xayb(v89AB, vCDEF);
    245   return v4f_xyab(v0415, v8C9D);
    246 }
    247 
    248 /*******************************************************************************
    249  * Bitwise operations
    250  ******************************************************************************/
    251 static FINLINE v4f_T
    252 v4f_or(const v4f_T v0, const v4f_T v1)
    253 {
    254   return _mm_or_ps(v0, v1);
    255 }
    256 
    257 static FINLINE v4f_T
    258 v4f_and(const v4f_T v0, const v4f_T v1)
    259 {
    260   return _mm_and_ps(v0, v1);
    261 }
    262 
    263 static FINLINE v4f_T
    264 v4f_andnot(const v4f_T v0, const v4f_T v1)
    265 {
    266   return _mm_andnot_ps(v0, v1);
    267 }
    268 
    269 static FINLINE v4f_T
    270 v4f_xor(const v4f_T v0, const v4f_T v1)
    271 {
    272   return _mm_xor_ps(v0, v1);
    273 }
    274 
    275 static FINLINE v4f_T
    276 v4f_sel(const v4f_T vfalse, const v4f_T vtrue, const v4f_T vcond)
    277 {
    278 #ifdef SIMD_SSE4_1
    279   return _mm_blendv_ps(vfalse, vtrue, vcond);
    280 #else
    281   return v4f_xor(vfalse, v4f_and(vcond, v4f_xor(vfalse, vtrue)));
    282 #endif
    283 }
    284 
    285 /*******************************************************************************
    286  * Arithmetic operations
    287  ******************************************************************************/
    288 static FINLINE v4f_T
    289 v4f_minus(const v4f_T v)
    290 {
    291   return v4f_xor(v4f_set1(-0.f), v);
    292 }
    293 
    294 static FINLINE v4f_T
    295 v4f_add(const v4f_T v0, const v4f_T v1)
    296 {
    297   return _mm_add_ps(v0, v1);
    298 }
    299 
    300 static FINLINE v4f_T
    301 v4f_sub(const v4f_T v0, const v4f_T v1)
    302 {
    303   return _mm_sub_ps(v0, v1);
    304 }
    305 
    306 static FINLINE v4f_T
    307 v4f_mul(const v4f_T v0, const v4f_T v1)
    308 {
    309   return _mm_mul_ps(v0, v1);
    310 }
    311 
    312 static FINLINE v4f_T
    313 v4f_div(const v4f_T v0, const v4f_T v1)
    314 {
    315   return _mm_div_ps(v0, v1);
    316 }
    317 
    318 static FINLINE v4f_T
    319 v4f_madd(const v4f_T v0, const v4f_T v1, const v4f_T v2)
    320 {
    321 #ifdef FMADD
    322   return _mm_fmadd_ps(v0, v1, v2);
    323 #else
    324   return _mm_add_ps(_mm_mul_ps(v0, v1), v2);
    325 #endif
    326 }
    327 
    328 static FINLINE v4f_T
    329 v4f_abs(const v4f_T v)
    330 {
    331   const union { int32_t i; float f; } mask = { 0x7fffffff };
    332   return v4f_and(v, v4f_set1(mask.f));
    333 }
    334 
    335 static FINLINE v4f_T
    336 v4f_sqrt(const v4f_T v)
    337 {
    338   return _mm_sqrt_ps(v);
    339 }
    340 
    341 static FINLINE v4f_T
    342 v4f_rsqrte(const v4f_T v)
    343 {
    344   return _mm_rsqrt_ps(v);
    345 }
    346 
    347 static FINLINE v4f_T
    348 v4f_rsqrt(const v4f_T v)
    349 {
    350   const v4f_T y = v4f_rsqrte(v);
    351   const v4f_T yyv = v4f_mul(v4f_mul(y, y), v);
    352   const v4f_T tmp = v4f_sub(v4f_set1(1.5f), v4f_mul(yyv, v4f_set1(0.5f)));
    353   return v4f_mul(tmp, y);
    354 }
    355 
    356 static FINLINE v4f_T
    357 v4f_rcpe(const v4f_T v)
    358 {
    359   return _mm_rcp_ps(v);
    360 }
    361 
    362 static FINLINE v4f_T
    363 v4f_rcp(const v4f_T v)
    364 {
    365   const v4f_T y = v4f_rcpe(v);
    366   const v4f_T tmp = v4f_sub(v4f_set1(2.f), v4f_mul(y, v));
    367   return v4f_mul(tmp, y);
    368 }
    369 
    370 static FINLINE v4f_T
    371 v4f_lerp(const v4f_T from, const v4f_T to, const v4f_T param)
    372 {
    373   return v4f_madd(v4f_sub(to, from), param, from);
    374 }
    375 
    376 static FINLINE v4f_T
    377 v4f_sum(const v4f_T v)
    378 {
    379 #if 0 /* SSE3 */
    380   const v4f_T r0 = _mm_hadd_ps(v, v);
    381   return _mm_hadd_ps(r0, r0);
    382 #else
    383   const v4f_T yxwz = v4f_yxwz(v);
    384   const v4f_T tmp0 = v4f_add(v, yxwz); /* x+y, y+x, z+w, w+z */
    385   const v4f_T tmp1 = v4f_wzyx(tmp0);   /* w+z, z+w, y+x, x+y */
    386   return v4f_add(tmp0, tmp1);
    387 #endif
    388 }
    389 
    390 static FINLINE v4f_T
    391 v4f_dot(const v4f_T v0, const v4f_T v1)
    392 {
    393   return v4f_sum(v4f_mul(v0, v1));
    394 }
    395 
    396 static FINLINE v4f_T
    397 v4f_len(const v4f_T v)
    398 {
    399   return v4f_sqrt(v4f_dot(v, v));
    400 }
    401 
    402 static FINLINE v4f_T
    403 v4f_normalize(const v4f_T v)
    404 {
    405   return v4f_mul(v, v4f_rsqrt(v4f_dot(v, v)));
    406 }
    407 
    408 static FINLINE v4f_T
    409 v4f_sum2(const v4f_T v)
    410 {
    411 #if 0 /* SSE3 */
    412   return v4f_xxxx(_mm_hadd_ps(v, v));
    413 #else
    414   return v4f_add(v4f_xxyy(v), v4f_yyxx(v));
    415 #endif
    416 }
    417 
    418 static FINLINE v4f_T
    419 v4f_dot2(const v4f_T v0, const v4f_T v1)
    420 {
    421   return v4f_sum2(v4f_mul(v0, v1));
    422 }
    423 
    424 static FINLINE v4f_T
    425 v4f_len2(const v4f_T v)
    426 {
    427   return v4f_sqrt(v4f_dot2(v, v));
    428 }
    429 
    430 static FINLINE v4f_T
    431 v4f_cross2(const v4f_T v0, const v4f_T v1)
    432 {
    433   const v4f_T v = v4f_mul(v0, v4f_yxyx(v1));
    434   return v4f_sub(v4f_xxxx(v), v4f_yyyy(v));
    435 }
    436 
    437 static FINLINE v4f_T
    438 v4f_normalize2(const v4f_T v)
    439 {
    440   return v4f_mul(v, v4f_rsqrt(v4f_dot2(v, v)));
    441 }
    442 
    443 static FINLINE v4f_T
    444 v4f_sum3(const v4f_T v)
    445 {
    446   const union { int32_t i; float f; } m = { ~0 };
    447   const v4f_T r0 = v4f_and(v4f_set(m.f, m.f, m.f, 0.f), v);
    448 #if 0 /* SSE3 */
    449   const v4f_T r1 = _mm_hadd_ps(r0, r0);
    450   return _mm_hadd_ps(r1, r1);
    451 #else
    452   return v4f_sum(r0);
    453 #endif
    454 }
    455 
    456 static FINLINE v4f_T
    457 v4f_dot3(const v4f_T v0, const v4f_T v1)
    458 {
    459   return v4f_sum3(v4f_mul(v0, v1));
    460 }
    461 
    462 static FINLINE v4f_T
    463 v4f_len3(const v4f_T v)
    464 {
    465   return v4f_sqrt(v4f_dot3(v, v));
    466 }
    467 
    468 static FINLINE v4f_T
    469 v4f_cross3(const v4f_T v0, const v4f_T v1)
    470 {
    471   const v4f_T r0 = v4f_mul(v0, v4f_yzxw(v1));
    472   const v4f_T r1 = v4f_mul(v1, v4f_yzxw(v0));
    473   return v4f_yzxw(v4f_sub(r0, r1));
    474 }
    475 
    476 static FINLINE v4f_T
    477 v4f_normalize3(const v4f_T v)
    478 {
    479   return v4f_mul(v, v4f_rsqrt(v4f_dot3(v, v)));
    480 }
    481 
    482 /*******************************************************************************
    483  * Comparators
    484  ******************************************************************************/
    485 static FINLINE v4f_T
    486 v4f_eq(const v4f_T v0, const v4f_T v1)
    487 {
    488   return _mm_cmpeq_ps(v0, v1);
    489 }
    490 
    491 static FINLINE v4f_T
    492 v4f_neq(const v4f_T v0, const v4f_T v1)
    493 {
    494   return _mm_cmpneq_ps(v0, v1);
    495 }
    496 
    497 static FINLINE v4f_T
    498 v4f_ge(const v4f_T v0, const v4f_T v1)
    499 {
    500   return _mm_cmpge_ps(v0, v1);
    501 }
    502 
    503 static FINLINE v4f_T
    504 v4f_le(const v4f_T v0, const v4f_T v1)
    505 {
    506   return _mm_cmple_ps(v0, v1);
    507 }
    508 
    509 static FINLINE v4f_T
    510 v4f_gt(const v4f_T v0, const v4f_T v1)
    511 {
    512   return _mm_cmpgt_ps(v0, v1);
    513 }
    514 
    515 static FINLINE v4f_T
    516 v4f_lt(const v4f_T v0, const v4f_T v1)
    517 {
    518   return _mm_cmplt_ps(v0, v1);
    519 }
    520 
    521 static FINLINE v4f_T
    522 v4f_eq_eps(const v4f_T v0, const v4f_T v1, const v4f_T eps)
    523 {
    524   return v4f_le(v4f_abs(v4f_sub(v0, v1)), eps);
    525 }
    526 
    527 static FINLINE v4f_T
    528 v4f_min(const v4f_T v0, const v4f_T v1)
    529 {
    530   return _mm_min_ps(v0, v1);
    531 }
    532 
    533 static FINLINE v4f_T
    534 v4f_max(const v4f_T v0, const v4f_T v1)
    535 {
    536   return _mm_max_ps(v0, v1);
    537 }
    538 
    539 static FINLINE v4f_T
    540 v4f_reduce_min(const v4f_T v)
    541 {
    542   const v4f_T tmp = v4f_min(v4f_yxwz(v), v);
    543   return v4f_min(v4f_zwxy(tmp), tmp);
    544 }
    545 
    546 static FINLINE v4f_T
    547 v4f_reduce_max(const v4f_T v)
    548 {
    549   const v4f_T tmp = v4f_max(v4f_yxwz(v), v);
    550   return v4f_max(v4f_zwxy(tmp), tmp);
    551 }
    552 
    553 static FINLINE v4f_T
    554 v4f_clamp(const v4f_T v, const v4f_T vmin, const v4f_T vmax)
    555 {
    556   return v4f_min(v4f_max(v, vmin), vmax);
    557 }
    558 
    559 #endif /* RSIMD_SSEF_H */
    560