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