yum-archive/TaSTT-Whisper
High-performance GPGPU inference of OpenAI's Whisper automatic speech recognition (ASR) model
git clone https://git.yummers.dev/yum-archive/TaSTT-Whisper
8c4603c
master
1#include "stdafx.h" 2#include "simdUtils.h" 3#include "../ML/LookupTablesData.h" 4#include <cmath> 5#include <memory> 6 7namespace 8{ 9constexpr size_t maskAlign8 = ~(size_t )7 ; 10 11 __forceinline__m256 load8 (const uint16_t * rsi ) 12 { 13__m128i i = _mm_loadu_si128 ( (const __m128i * )rsi ); 14return _mm256_cvtph_ps (i ); 15 } 16 17 __forceinlinevoid loadPartial (const uint16_t * x ,const uint16_t * y ,size_t count ,__m256 & fx ,__m256 & fy ) 18 { 19assert (count < 8 ); 20 21__m128i ix ,iy ; 22switch (count ) 23 { 24case 1 :// load 2 bytes 25ix = _mm_cvtsi32_si128 (* x ); 26iy = _mm_cvtsi32_si128 (* y ); 27break ; 28case 2 :// load 4 bytes 29ix = _mm_cvtsi32_si128 (* (const int * )x ); 30iy = _mm_cvtsi32_si128 (* (const int * )y ); 31break ; 32case 3 :// load 6 bytes 33ix = _mm_cvtsi32_si128 (* (const int * )x ); 34iy = _mm_cvtsi32_si128 (* (const int * )y ); 35ix = _mm_insert_epi16 (ix ,x [2 ],2 ); 36iy = _mm_insert_epi16 (iy ,y [2 ],2 ); 37break ; 38case 4 :// load 8 bytes 39ix = _mm_cvtsi64_si128 (* (const int64_t * )x ); 40iy = _mm_cvtsi64_si128 (* (const int64_t * )y ); 41break ; 42case 5 :// load 10 bytes 43ix = _mm_cvtsi64_si128 (* (const int64_t * )x ); 44iy = _mm_cvtsi64_si128 (* (const int64_t * )y ); 45ix = _mm_insert_epi16 (ix ,x [4 ],4 ); 46iy = _mm_insert_epi16 (iy ,y [4 ],4 ); 47break ; 48case 6 :// load 12 bytes 49ix = _mm_cvtsi64_si128 (* (const int64_t * )x ); 50iy = _mm_cvtsi64_si128 (* (const int64_t * )y ); 51ix = _mm_insert_epi32 (ix ,* (const int * )(x + 4 ),2 ); 52iy = _mm_insert_epi32 (iy ,* (const int * )(y + 4 ),2 ); 53break ; 54case 7 :// load 14 bytes 55ix = _mm_cvtsi64_si128 (* (const int64_t * )x ); 56iy = _mm_cvtsi64_si128 (* (const int64_t * )y ); 57ix = _mm_insert_epi32 (ix ,* (const int * )(x + 4 ),2 ); 58iy = _mm_insert_epi32 (iy ,* (const int * )(y + 4 ),2 ); 59ix = _mm_insert_epi16 (ix ,x [6 ],6 ); 60iy = _mm_insert_epi16 (iy ,y [6 ],6 ); 61break ; 62default : 63fx = fy = _mm256_setzero_ps (); 64return ; 65 } 66 67fx = _mm256_cvtph_ps (ix ); 68fy = _mm256_cvtph_ps (iy ); 69 } 70 71 __forceinline__m256 loadPartial (const uint16_t * x ,size_t count ) 72 { 73assert (count < 8 ); 74__m128i ix ; 75switch (count ) 76 { 77case 1 :// load 2 bytes 78ix = _mm_cvtsi32_si128 (* x ); 79break ; 80case 2 :// load 4 bytes 81ix = _mm_cvtsi32_si128 (* (const int * )x ); 82break ; 83case 3 :// load 6 bytes 84ix = _mm_cvtsi32_si128 (* (const int * )x ); 85ix = _mm_insert_epi16 (ix ,x [2 ],2 ); 86break ; 87case 4 :// load 8 bytes 88ix = _mm_cvtsi64_si128 (* (const int64_t * )x ); 89break ; 90case 5 :// load 10 bytes 91ix = _mm_cvtsi64_si128 (* (const int64_t * )x ); 92ix = _mm_insert_epi16 (ix ,x [4 ],4 ); 93break ; 94case 6 :// load 12 bytes 95ix = _mm_cvtsi64_si128 (* (const int64_t * )x ); 96ix = _mm_insert_epi32 (ix ,* (const int * )(x + 4 ),2 ); 97break ; 98case 7 :// load 14 bytes 99ix = _mm_cvtsi64_si128 (* (const int64_t * )x ); 100ix = _mm_insert_epi32 (ix ,* (const int * )(x + 4 ),2 ); 101ix = _mm_insert_epi16 (ix ,x [6 ],6 ); 102break ; 103default : 104return _mm256_setzero_ps (); 105 } 106return _mm256_cvtph_ps (ix ); 107 } 108 109 __forceinline__m128 loadFloat2 (const float * rsi ) 110 { 111return _mm_castpd_ps (_mm_load_sd ( (const double * )rsi ) ); 112 } 113 __forceinline__m128 loadFloat3 (const float * rsi ) 114 { 115__m128 f = loadFloat2 (rsi ); 116f = _mm_insert_ps (f ,_mm_load_ss (rsi + 2 ),0x20 ); 117return f ; 118 } 119 120 __forceinline__m256 loadPartial (const float * rsi ,size_t count ) 121 { 122assert (count < 8 ); 123__m128 low = _mm_setzero_ps (); 124__m128 high = _mm_setzero_ps (); 125switch (count ) 126 { 127case 1 : 128low = _mm_load_ss (rsi ); 129break ; 130case 2 : 131low = loadFloat2 (rsi ); 132break ; 133case 3 : 134low = loadFloat3 (rsi ); 135break ; 136case 4 : 137low = _mm_loadu_ps (rsi ); 138break ; 139case 5 : 140low = _mm_loadu_ps (rsi ); 141high = _mm_load_ss (rsi + 4 ); 142break ; 143case 6 : 144low = _mm_loadu_ps (rsi ); 145high = loadFloat2 (rsi + 4 ); 146break ; 147case 7 : 148low = _mm_loadu_ps (rsi ); 149high = loadFloat3 (rsi + 4 ); 150break ; 151 } 152return _mm256_setr_m128 (low ,high ); 153 } 154 155 __forceinlinevoid storeFloat2 (float * rdi ,__m128 vec ) 156 { 157_mm_store_sd ( (double * )rdi ,_mm_castps_pd (vec ) ); 158 } 159 160 __forceinlinevoid storePartial (float * rdi ,__m256 vec ,size_t count ) 161 { 162assert (count < 8 ); 163 164__m128 tmp = _mm256_castps256_ps128 (vec ); 165if (count >=4 ) 166 { 167_mm_storeu_ps (rdi ,tmp ); 168if (count == 4 ) 169return ; 170count -= 4 ; 171rdi += 4 ; 172tmp = _mm256_extractf128_ps (vec ,1 ); 173 } 174 175switch (count ) 176 { 177case 1 : 178_mm_store_ss (rdi ,tmp ); 179return ; 180case 2 : 181storeFloat2 (rdi ,tmp ); 182return ; 183case 3 : 184storeFloat2 (rdi ,tmp ); 185 ( (int * )rdi )[2 ]= _mm_extract_ps (tmp ,2 ); 186return ; 187 } 188 } 189} 190 191void addF16to32 (float * rdi ,const uint16_t * a ,const uint16_t * b ,size_t length ) 192{ 193const uint16_t * const endAligned = a + (length & maskAlign8 ); 194const size_t rem = length %8 ; 195 196for ( ;a < endAligned ;a += 8 ,b += 8 ,rdi += 8 ) 197 { 198__m256 f1 = load8 (a ); 199__m256 f2 = load8 (b ); 200__m256 res = _mm256_add_ps (f1 ,f2 ); 201_mm256_storeu_ps (rdi ,res ); 202 } 203 204if (rem != 0 ) 205 { 206__m256 f1 ,f2 ; 207loadPartial (a ,b ,rem ,f1 ,f2 ); 208__m256 res = _mm256_add_ps (f1 ,f2 ); 209storePartial (rdi ,res ,rem ); 210 } 211} 212 213void addF16to32 (float * rdi ,const uint16_t * a ,const float * b ,size_t length ) 214{ 215const uint16_t * const endAligned = a + (length & maskAlign8 ); 216const size_t rem = length %8 ; 217 218for ( ;a < endAligned ;a += 8 ,b += 8 ,rdi += 8 ) 219 { 220__m256 f1 = load8 (a ); 221__m256 f2 = _mm256_loadu_ps (b ); 222__m256 res = _mm256_add_ps (f1 ,f2 ); 223_mm256_storeu_ps (rdi ,res ); 224 } 225 226if (rem != 0 ) 227 { 228__m256 f1 = loadPartial (a ,rem ); 229__m256 f2 = loadPartial (b ,rem ); 230__m256 res = _mm256_add_ps (f1 ,f2 ); 231storePartial (rdi ,res ,rem ); 232 } 233} 234 235alignas(64 )const std::array < int ,16 > s_zeroTailMask = 236{ 237-1 ,-1 ,-1 ,-1 ,-1 ,-1 ,-1 ,-1 , 2380 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , 239}; 240 241namespace 242{ 243 __forceinlinefloat horizontalSum (__m256 vec ) 244 { 245__m128 v = _mm256_extractf128_ps (vec ,1 ); 246v = _mm_add_ps (v ,_mm256_castps256_ps128 (vec ) ); 247v = _mm_add_ps (v ,_mm_movehl_ps (v ,v ) ); 248v = _mm_add_ss (v ,_mm_movehdup_ps (v ) ); 249return _mm_cvtss_f32 (v ); 250 } 251} 252 253void norm (float * rdi ,float * temp ,const float * rsi ,size_t length ) 254{ 255assert ( (size_t )temp %32 == 0 ); 256const float * rsiEndAligned = rsi + (length & maskAlign8 ); 257const size_t rem = length %8 ; 258 259// First pass: copy to temp buffer, and compute the sum; computeVectorSum() in HLSL 260__m256 sum = _mm256_setzero_ps (); 261float * t ; 262for (t = temp ;rsi < rsiEndAligned ;rsi += 8 ,t += 8 ) 263 { 264__m256 v = _mm256_loadu_ps (rsi ); 265sum = _mm256_add_ps (sum ,v ); 266_mm256_store_ps (t ,v ); 267 } 268float * const tEndAligned = t ; 269if (0 != rem ) 270 { 271__m256 v = loadPartial (rsi ,rem ); 272sum = _mm256_add_ps (sum ,v ); 273_mm256_store_ps (t ,v ); 274t += 8 ; 275 } 276 277const float lengthFloat = (float )(int )length ; 278const float meanScalar = horizontalSum (sum ) /lengthFloat ; 279const __m256 mean = _mm256_set1_ps (meanScalar ); 280 281// Second pass, offsetAndComputeSumSquares() in HLSL 282sum = _mm256_setzero_ps (); 283for (t = temp ;t < tEndAligned ;t += 8 ) 284 { 285__m256 v = _mm256_load_ps (t ); 286v = _mm256_sub_ps (v ,mean ); 287_mm256_store_ps (t ,v ); 288sum = _mm256_fmadd_ps (v ,v ,sum ); 289 } 290if (0 != rem ) 291 { 292__m256 v = _mm256_load_ps (t ); 293v = _mm256_sub_ps (v ,mean ); 294v = _mm256_and_ps (v ,loadTailMaskFloats (rem ) ); 295_mm256_store_ps (t ,v ); 296sum = _mm256_fmadd_ps (v ,v ,sum ); 297 } 298 299// Final pass: scale, and copy from temporary buffer into the destination row 300 301constexpr float eps = 1e-5f ;// TODO: make this a parameter 302const float scaleScalar = 1.0f / std::sqrtf (horizontalSum (sum ) /lengthFloat + eps ); 303const __m256 scale = _mm256_set1_ps (scaleScalar ); 304 305for (t = temp ;t < tEndAligned ;t += 8 ,rdi += 8 ) 306 { 307__m256 v = _mm256_load_ps (t ); 308v = _mm256_mul_ps (v ,scale ); 309_mm256_storeu_ps (rdi ,v ); 310 } 311if (0 != rem ) 312 { 313__m256 v = _mm256_load_ps (t ); 314v = _mm256_mul_ps (v ,scale ); 315storePartial (rdi ,v ,rem ); 316 } 317} 318 319void fmaRepeatRow (float * rdi ,size_t len ,const float * w ,const float * b ,size_t lenPattern ) 320{ 321float * rdiEndAligned = rdi + (len & maskAlign8 ); 322const size_t rem = len %8 ; 323 324if (1 == lenPattern ) 325 { 326const __m256 v1 = _mm256_broadcast_ss (w ); 327const __m256 v2 = _mm256_broadcast_ss (b ); 328for ( ;rdi < rdiEndAligned ;rdi += 8 ) 329 { 330__m256 v = _mm256_loadu_ps (rdi ); 331v = _mm256_fmadd_ps (v ,v1 ,v2 ); 332_mm256_storeu_ps (rdi ,v ); 333 } 334if (0 != rem ) 335 { 336const __m256i mask = loadTailMaskInt (rem ); 337__m256 v = _mm256_maskload_ps (rdi ,mask ); 338v = _mm256_fmadd_ps (v ,v1 ,v2 ); 339_mm256_maskstore_ps (rdi ,mask ,v ); 340 } 341 } 342else if (len == lenPattern ) 343 { 344for ( ;rdi < rdiEndAligned ;rdi += 8 ,w += 8 ,b += 8 ) 345 { 346__m256 v = _mm256_loadu_ps (rdi ); 347__m256 v1 = _mm256_loadu_ps (w ); 348__m256 v2 = _mm256_loadu_ps (b ); 349v = _mm256_fmadd_ps (v ,v1 ,v2 ); 350_mm256_storeu_ps (rdi ,v ); 351 } 352if (0 != rem ) 353 { 354const __m256i mask = loadTailMaskInt (rem ); 355__m256 v = _mm256_maskload_ps (rdi ,mask ); 356__m256 v1 = _mm256_maskload_ps (w ,mask ); 357__m256 v2 = _mm256_maskload_ps (b ,mask ); 358v = _mm256_fmadd_ps (v ,v1 ,v2 ); 359_mm256_maskstore_ps (rdi ,mask ,v ); 360 } 361 } 362else 363 { 364// TODO: implement if this actually happens 365throw E_NOTIMPL ; 366 } 367} 368 369void __vectorcalladdRepeatScaleRow (float * rdi ,size_t len ,const float * b ,size_t lenPattern ,const __m256 scale ) 370{ 371float * rdiEndAligned = rdi + (len & maskAlign8 ); 372const size_t rem = len %8 ; 373 374if (1 == lenPattern ) 375 { 376const __m256 v2 = _mm256_broadcast_ss (b ); 377for ( ;rdi < rdiEndAligned ;rdi += 8 ) 378 { 379__m256 v = _mm256_loadu_ps (rdi ); 380v = _mm256_add_ps (v ,v2 ); 381v = _mm256_mul_ps (v ,scale ); 382_mm256_storeu_ps (rdi ,v ); 383 } 384if (0 != rem ) 385 { 386const __m256i mask = loadTailMaskInt (rem ); 387__m256 v = _mm256_maskload_ps (rdi ,mask ); 388v = _mm256_add_ps (v ,v2 ); 389v = _mm256_mul_ps (v ,scale ); 390_mm256_maskstore_ps (rdi ,mask ,v ); 391 } 392return ; 393 } 394else if (len == lenPattern ) 395 { 396for ( ;rdi < rdiEndAligned ;rdi += 8 ,b += 8 ) 397 { 398__m256 v = _mm256_loadu_ps (rdi ); 399__m256 v2 = _mm256_loadu_ps (b ); 400v = _mm256_add_ps (v ,v2 ); 401v = _mm256_mul_ps (v ,scale ); 402_mm256_storeu_ps (rdi ,v ); 403 } 404if (0 != rem ) 405 { 406const __m256i mask = loadTailMaskInt (rem ); 407__m256 v = _mm256_maskload_ps (rdi ,mask ); 408__m256 v2 = _mm256_maskload_ps (b ,mask ); 409v = _mm256_add_ps (v ,v2 ); 410v = _mm256_mul_ps (v ,scale ); 411_mm256_maskstore_ps (rdi ,mask ,v ); 412 } 413return ; 414 } 415else 416 { 417// TODO: implement if this actually happens 418throw E_NOTIMPL ; 419 } 420} 421 422void addRepeatRow (float * rdi ,size_t len ,const float * b ,size_t lenPattern ) 423{ 424float * rdiEndAligned = rdi + (len & maskAlign8 ); 425const size_t rem = len %8 ; 426 427if (1 == lenPattern ) 428 { 429const __m256 v2 = _mm256_broadcast_ss (b ); 430for ( ;rdi < rdiEndAligned ;rdi += 8 ) 431 { 432__m256 v = _mm256_loadu_ps (rdi ); 433v = _mm256_add_ps (v ,v2 ); 434_mm256_storeu_ps (rdi ,v ); 435 } 436if (0 != rem ) 437 { 438const __m256i mask = loadTailMaskInt (rem ); 439__m256 v = _mm256_maskload_ps (rdi ,mask ); 440v = _mm256_add_ps (v ,v2 ); 441_mm256_maskstore_ps (rdi ,mask ,v ); 442 } 443return ; 444 } 445else if (len == lenPattern ) 446 { 447for ( ;rdi < rdiEndAligned ;rdi += 8 ,b += 8 ) 448 { 449__m256 v = _mm256_loadu_ps (rdi ); 450__m256 v2 = _mm256_loadu_ps (b ); 451v = _mm256_add_ps (v ,v2 ); 452_mm256_storeu_ps (rdi ,v ); 453 } 454if (0 != rem ) 455 { 456const __m256i mask = loadTailMaskInt (rem ); 457__m256 v = _mm256_maskload_ps (rdi ,mask ); 458__m256 v2 = _mm256_maskload_ps (b ,mask ); 459v = _mm256_add_ps (v ,v2 ); 460_mm256_maskstore_ps (rdi ,mask ,v ); 461 } 462return ; 463 } 464else 465 { 466// TODO: implement if this actually happens 467throw E_NOTIMPL ; 468 } 469} 470 471namespace 472{ 473 __forceinline__m256 gelu (__m256 x ,const DirectCompute ::LookupTablesData & lookup ) 474 { 475__m128i iv = _mm256_cvtps_ph (x ,0 ); 476 alignas(16 ) std::array < uint16_t ,8 > arr ; 477_mm_store_si128 ( (__m128i * )arr .data (),iv ); 478for (uint16_t & a :arr ) 479a = lookup .gelu [a ]; 480iv = _mm_load_si128 ( (__m128i * )arr .data () ); 481return _mm256_cvtph_ps (iv ); 482 } 483} 484 485void addRepeatGeluRow (float * rdi ,size_t len ,const float * b ,size_t lenPattern ,const DirectCompute ::LookupTablesData & lookup ) 486{ 487float * rdiEndAligned = rdi + (len & maskAlign8 ); 488const size_t rem = len %8 ; 489 490if (1 == lenPattern ) 491 { 492const __m256 v2 = _mm256_broadcast_ss (b ); 493for ( ;rdi < rdiEndAligned ;rdi += 8 ) 494 { 495__m256 v = _mm256_loadu_ps (rdi ); 496v = _mm256_add_ps (v ,v2 ); 497v = gelu (v ,lookup ); 498_mm256_storeu_ps (rdi ,v ); 499 } 500if (0 != rem ) 501 { 502const __m256i mask = loadTailMaskInt (rem ); 503__m256 v = _mm256_maskload_ps (rdi ,mask ); 504v = _mm256_add_ps (v ,v2 ); 505v = gelu (v ,lookup ); 506_mm256_maskstore_ps (rdi ,mask ,v ); 507 } 508return ; 509 } 510else if (len == lenPattern ) 511 { 512for ( ;rdi < rdiEndAligned ;rdi += 8 ,b += 8 ) 513 { 514__m256 v = _mm256_loadu_ps (rdi ); 515__m256 v2 = _mm256_loadu_ps (b ); 516v = _mm256_add_ps (v ,v2 ); 517v = gelu (v ,lookup ); 518_mm256_storeu_ps (rdi ,v ); 519 } 520if (0 != rem ) 521 { 522const __m256i mask = loadTailMaskInt (rem ); 523__m256 v = _mm256_maskload_ps (rdi ,mask ); 524__m256 v2 = _mm256_maskload_ps (b ,mask ); 525v = _mm256_add_ps (v ,v2 ); 526v = gelu (v ,lookup ); 527_mm256_maskstore_ps (rdi ,mask ,v ); 528 } 529return ; 530 } 531else 532 { 533// TODO: implement if this actually happens 534throw E_NOTIMPL ; 535 } 536} 537 538void __vectorcallscaleRow (float * rdi ,size_t len ,const __m256 scale ) 539{ 540float * rdiEndAligned = rdi + (len & maskAlign8 ); 541const size_t rem = len %8 ; 542for ( ;rdi < rdiEndAligned ;rdi += 8 ) 543 { 544__m256 v = _mm256_loadu_ps (rdi ); 545v = _mm256_mul_ps (v ,scale ); 546_mm256_storeu_ps (rdi ,v ); 547 } 548if (0 != rem ) 549 { 550const __m256i mask = loadTailMaskInt (rem ); 551__m256 v = _mm256_maskload_ps (rdi ,mask ); 552v = _mm256_mul_ps (v ,scale ); 553_mm256_maskstore_ps (rdi ,mask ,v ); 554 } 555} 556 557namespace 558{ 559using DirectCompute ::LookupTablesData ; 560 561 __forceinlinefloat horizontalMax (__m256 vec ) 562 { 563__m128 v = _mm256_extractf128_ps (vec ,1 ); 564v = _mm_max_ps (v ,_mm256_castps256_ps128 (vec ) ); 565v = _mm_max_ps (v ,_mm_movehl_ps (v ,v ) ); 566v = _mm_max_ss (v ,_mm_movehdup_ps (v ) ); 567return _mm_cvtss_f32 (v ); 568 } 569 570 __forceinlinefloat _cvtsh_ss (uint16_t f16 ) 571 { 572__m128i i = _mm_cvtsi32_si128 (f16 ); 573__m128 f = _mm_cvtph_ps (i ); 574return _mm_cvtss_f32 (f ); 575 } 576 577 __forceinlineuint16_t _cvtss_sh (float f ,int rounding ) 578 { 579assert (0 == rounding ); 580__m128 v = _mm_set_ss (f ); 581__m128i i = _mm_cvtps_ph (v ,0 ); 582return (uint16_t )(uint32_t )_mm_cvtsi128_si32 (i ); 583 } 584} 585 586const LookupTablesData & getLookupTables () 587{ 588static const std::unique_ptr < LookupTablesData > res = std::make_unique < LookupTablesData > (); 589return * res ; 590} 591 592void softMax (float * rdi ,size_t length ,const float inputScale ) 593{ 594float * const rdiBegin = rdi ; 595float * const rdiEndAligned = rdi + (length & maskAlign8 ); 596const size_t remainder = length %8 ; 597// First pass, compute maximum 598__m256 max = _mm256_set1_ps (- INFINITY ); 599for (rdi = rdiBegin ;rdi < rdiEndAligned ;rdi += 8 ) 600 { 601__m256 v = _mm256_loadu_ps (rdi ); 602max = _mm256_max_ps (max ,v ); 603 } 604__m256i tailMask ; 605if (0 != remainder ) 606 { 607tailMask = loadTailMaskInt (remainder ); 608__m256 v = _mm256_maskload_ps (rdi ,tailMask ); 609v = _mm256_max_ps (max ,v ); 610max = _mm256_blendv_ps (max ,v ,_mm256_castsi256_ps (tailMask ) ); 611 } 612 613// Second pass: apply initial scale, compute the exponent, and compute total sum over the row 614const LookupTablesData & lookup = getLookupTables (); 615const float maxScalar = horizontalMax (max ); 616 617float * const rdiEnd = rdiBegin + length ; 618double sum = 0 ; 619for (rdi = rdiBegin ;rdi < rdiEnd ;rdi ++ ) 620 { 621// Possible to vectorize, but relatively hard 622// An easy way is upcast the complete lookup table to FP32 and then use two _mm256_i32gather_ps instructions per iteration 623// However, that instruction is from AVX2 set. Let's hope this loop won't be a bottleneck. 624float f = * rdi ; 625if (f != - INFINITY ) 626 { 627f = (f - maxScalar )* inputScale ; 628uint16_t f16 = _cvtss_sh (f ,0 ); 629f16 = lookup .exponent [f16 ]; 630f = _cvtsh_ss (f16 ); 631sum += f ; 632 } 633else 634f = 0 ; 635 636* rdi = f ; 637 } 638 639// Final pass: apply the final scale 640const __m256 finalScale = _mm256_set1_ps ( (float )(1.0 /sum ) ); 641for (rdi = rdiBegin ;rdi < rdiEndAligned ;rdi += 8 ) 642 { 643__m256 v = _mm256_loadu_ps (rdi ); 644v = _mm256_mul_ps (v ,finalScale ); 645_mm256_storeu_ps (rdi ,v ); 646 } 647if (0 != remainder ) 648 { 649__m256 v = _mm256_maskload_ps (rdi ,tailMask ); 650v = _mm256_mul_ps (v ,finalScale ); 651_mm256_maskstore_ps (rdi ,tailMask ,v ); 652 } 653} 654 655void floatsUpcast (float * rdi ,const uint16_t * rsi ,size_t length ) 656{ 657const uint16_t * rsiEndAligned = rsi + (length & maskAlign8 ); 658const size_t rem = length %8 ; 659 660for ( ;rsi < rsiEndAligned ;rsi += 8 ,rdi += 8 ) 661_mm256_storeu_ps (rdi ,load8 (rsi ) ); 662 663if (0 != rem ) 664 { 665__m256 v = loadPartial (rsi ,rem ); 666_mm256_maskstore_ps (rdi ,loadTailMaskInt (rem ),v ); 667 } 668} 669 670void floatsDowncast (uint16_t * rdi ,const float * rsi ,size_t length ) 671{ 672const float * rsiEndAligned = rsi + (length & maskAlign8 ); 673size_t rem = length %8 ; 674 675for ( ;rsi < rsiEndAligned ;rsi += 8 ,rdi += 8 ) 676 { 677__m256 vf = _mm256_loadu_ps (rsi ); 678__m128i vi = _mm256_cvtps_ph (vf ,0 ); 679store16 (rdi ,vi ); 680 } 681 682if (0 != rem ) 683 { 684__m256 vf = _mm256_maskload_ps (rsi ,loadTailMaskInt (rem ) ); 685__m128i vi = _mm256_cvtps_ph (vf ,0 ); 686for (size_t i = 0 ;i < rem ;i ++ ,rdi ++ ) 687 { 688* rdi = (uint16_t )(uint32_t )_mm_cvtsi128_si32 (vi ); 689vi = _mm_srli_si128 (vi ,2 ); 690 } 691 } 692} 693 694void addRowInPlace (float * rdi ,const float * rsi ,size_t length ) 695{ 696const float * rdiEndAligned = rdi + (length & maskAlign8 ); 697size_t rem = length %8 ; 698 699for ( ;rdi < rdiEndAligned ;rdi += 8 ,rsi += 8 ) 700 { 701__m256 a = _mm256_loadu_ps (rdi ); 702__m256 b = _mm256_loadu_ps (rsi ); 703a = _mm256_add_ps (a ,b ); 704_mm256_storeu_ps (rdi ,a ); 705 } 706 707if (0 != rem ) 708 { 709const __m256i mask = loadTailMaskInt (rem ); 710__m256 a = _mm256_maskload_ps (rdi ,mask ); 711__m256 b = _mm256_maskload_ps (rsi ,mask ); 712a = _mm256_add_ps (a ,b ); 713_mm256_maskstore_ps (rdi ,mask ,a ); 714 } 715} 716 717void addRow (float * rdi ,const float * a ,const float * b ,size_t length ) 718{ 719const float * aEndAligned = a + (length & maskAlign8 ); 720size_t rem = length %8 ; 721 722for ( ;a < aEndAligned ;a += 8 ,b += 8 ,rdi += 8 ) 723 { 724__m256 x = _mm256_loadu_ps (a ); 725__m256 y = _mm256_loadu_ps (b ); 726x = _mm256_add_ps (x ,y ); 727_mm256_storeu_ps (rdi ,x ); 728 } 729 730if (0 != rem ) 731 { 732const __m256i mask = loadTailMaskInt (rem ); 733__m256 x = _mm256_maskload_ps (a ,mask ); 734__m256 y = _mm256_maskload_ps (b ,mask ); 735x = _mm256_add_ps (x ,y ); 736_mm256_maskstore_ps (rdi ,mask ,x ); 737 } 738}