30 for (
size_t i = 0; i < n; i++) {
31 if (a[i] != b[i])
return false;
37 for (
size_t i = 0; i < n; i++) {
38 if (a[i] != b[i])
return false;
43inline bool compare_f32(
const float* a,
const float* b,
size_t n,
float eps = 0.001f) {
44 for (
size_t i = 0; i < n; i++) {
45 float diff = a[i] - b[i];
46 if (diff < -eps || diff > eps)
return false;
60 uint8_t input[16] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
63 store_u8_16(output, v);
68 uint8_t input[16] = {0,255,0,255, 0,255,0,255, 0,255,0,255, 0,255,0,255};
71 store_u8_16(output, v);
80 uint32_t input[4] = {0x12345678, 0x9ABCDEF0, 0xFEDCBA98, 0x76543210};
83 store_u32_4(output, v);
88 uint32_t input[4] = {0, 0xFFFFFFFF, 1, 0x80000000};
91 store_u32_4(output, v);
99 store_u32_4_aligned(output, v);
108 float input[4] = {1.5f, 2.5f, 3.5f, 4.5f};
109 float output[4] = {0.0f};
111 store_f32_4(output, v);
116 float input[4] = {0.0f, -0.0f, 1e30f, -1e30f};
117 float output[4] = {0.0f};
119 store_f32_4(output, v);
121 for (
int i = 0; i < 4; i++) {
122 float diff = input[i] - output[i];
123 if (diff < -0.001f || diff > 0.001f)
return false;
133 uint8_t a[16] = {100,150,200,250, 100,150,200,250, 100,150,200,250, 100,150,200,250};
134 uint8_t b[16] = {50,100,50,100, 50,100,50,100, 50,100,50,100, 50,100,50,100};
135 uint8_t expected[16] = {150,250,250,255, 150,250,250,255, 150,250,250,255, 150,250,250,255};
139 store_u8_16(output, add_sat_u8_16(va, vb));
145 uint8_t a[16] = {255,255,0,0, 128,1,254,255, 255,255,0,0, 128,1,254,255};
146 uint8_t b[16] = {255,1,0,0, 128,255,2,0, 255,1,0,0, 128,255,2,0};
147 uint8_t expected[16] = {255,255,0,0, 255,255,255,255, 255,255,0,0, 255,255,255,255};
149 store_u8_16(output, add_sat_u8_16(load_u8_16(a), load_u8_16(b)));
154 uint8_t a[16] = {100,50,200,10, 100,50,200,10, 100,50,200,10, 100,50,200,10};
155 uint8_t b[16] = {50,100,50,100, 50,100,50,100, 50,100,50,100, 50,100,50,100};
156 uint8_t expected[16] = {50,0,150,0, 50,0,150,0, 50,0,150,0, 50,0,150,0};
158 store_u8_16(output, sub_sat_u8_16(load_u8_16(a), load_u8_16(b)));
164 uint8_t a[16] = {0,255,100,0, 1,0,0,0, 0,255,100,0, 1,0,0,0};
165 uint8_t b[16] = {255,0,100,0, 0,1,255,128, 255,0,100,0, 0,1,255,128};
166 uint8_t expected[16] = {0,255,0,0, 1,0,0,0, 0,255,0,0, 1,0,0,0};
168 store_u8_16(output, sub_sat_u8_16(load_u8_16(a), load_u8_16(b)));
177 uint8_t a[16] = {255,128,64,32, 255,128,64,32, 255,128,64,32, 255,128,64,32};
179 store_u8_16(output, scale_u8_16(load_u8_16(a), 128));
180 for (
int i = 0; i < 16; i++) {
182 int diff = (int)output[i] -
expected;
183 if (diff < -1 || diff > 1)
return false;
189 uint8_t a[16] = {255,128,64,32, 255,128,64,32, 255,128,64,32, 255,128,64,32};
190 uint8_t expected[16] = {0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0};
192 store_u8_16(output, scale_u8_16(load_u8_16(a), 0));
198 uint8_t a[16] = {255,128,64,32, 10,200,100,50, 255,128,64,32, 10,200,100,50};
200 store_u8_16(output, scale_u8_16(load_u8_16(a), 255));
201 for (
int i = 0; i < 16; i++) {
203 int diff = (int)output[i] -
expected;
204 if (diff < -1 || diff > 1)
return false;
210 uint8_t a[16] = {0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0};
211 uint8_t b[16] = {255,255,255,255, 255,255,255,255, 255,255,255,255, 255,255,255,255};
213 store_u8_16(output, blend_u8_16(load_u8_16(a), load_u8_16(b), 128));
214 for (
int i = 0; i < 16; i++) {
215 int diff = (int)output[i] - 128;
216 if (diff < -2 || diff > 2)
return false;
223 uint8_t a[16] = {100,100,100,100, 100,100,100,100, 100,100,100,100, 100,100,100,100};
224 uint8_t b[16] = {200,200,200,200, 200,200,200,200, 200,200,200,200, 200,200,200,200};
227 store_u8_16(output0, blend_u8_16(load_u8_16(a), load_u8_16(b), 0));
228 store_u8_16(output255, blend_u8_16(load_u8_16(a), load_u8_16(b), 255));
229 for (
int i = 0; i < 16; i++) {
230 if (output0[i] != 100)
return false;
231 int diff = (int)output255[i] - 200;
232 if (diff < -2 || diff > 2)
return false;
242 uint8_t a[16] = {10,200,30,240, 0,255,1,254, 10,200,30,240, 0,255,1,254};
243 uint8_t b[16] = {20,100,40,120, 0,0,255,255, 20,100,40,120, 0,0,255,255};
244 uint8_t expected[16] = {10,100,30,120, 0,0,1,254, 10,100,30,120, 0,0,1,254};
246 store_u8_16(output, min_u8_16(load_u8_16(a), load_u8_16(b)));
251 uint8_t a[16] = {10,200,30,240, 0,255,1,254, 10,200,30,240, 0,255,1,254};
252 uint8_t b[16] = {20,100,40,120, 0,0,255,255, 20,100,40,120, 0,0,255,255};
253 uint8_t expected[16] = {20,200,40,240, 0,255,255,255, 20,200,40,240, 0,255,255,255};
255 store_u8_16(output, max_u8_16(load_u8_16(a), load_u8_16(b)));
260 uint8_t a[16] = {100,200,50,0, 255,0,1,254, 100,200,50,0, 255,0,1,254};
261 uint8_t b[16] = {200,100,150,0, 255,0,1,254, 200,100,150,0, 255,0,1,254};
263 store_u8_16(output, avg_u8_16(load_u8_16(a), load_u8_16(b)));
264 for (
int i = 0; i < 16; i++) {
266 int diff = (int)output[i] -
expected;
267 if (diff < -1 || diff > 1)
return false;
273 uint8_t a[16] = {101,201,51,1, 255,0,3,253, 101,201,51,1, 255,0,3,253};
274 uint8_t b[16] = {200,100,150,0, 254,1,2,252, 200,100,150,0, 254,1,2,252};
276 store_u8_16(output, avg_round_u8_16(load_u8_16(a), load_u8_16(b)));
277 for (
int i = 0; i < 16; i++) {
278 int expected = (a[i] + b[i] + 1) / 2;
279 int diff = (int)output[i] -
expected;
280 if (diff < -1 || diff > 1)
return false;
290 uint8_t a[16] = {0xFF,0x0F,0xF0,0xAA, 0xFF,0x0F,0xF0,0xAA, 0xFF,0x0F,0xF0,0xAA, 0xFF,0x0F,0xF0,0xAA};
291 uint8_t b[16] = {0x0F,0xFF,0xFF,0x55, 0x0F,0xFF,0xFF,0x55, 0x0F,0xFF,0xFF,0x55, 0x0F,0xFF,0xFF,0x55};
292 uint8_t expected[16] = {0x0F,0x0F,0xF0,0x00, 0x0F,0x0F,0xF0,0x00, 0x0F,0x0F,0xF0,0x00, 0x0F,0x0F,0xF0,0x00};
294 store_u8_16(output, and_u8_16(load_u8_16(a), load_u8_16(b)));
299 uint8_t a[16] = {0xFF,0x0F,0xF0,0xAA, 0x00,0x00,0xFF,0x80, 0xFF,0x0F,0xF0,0xAA, 0x00,0x00,0xFF,0x80};
300 uint8_t b[16] = {0x0F,0xFF,0xFF,0x55, 0x00,0xFF,0x00,0x01, 0x0F,0xFF,0xFF,0x55, 0x00,0xFF,0x00,0x01};
301 uint8_t expected[16] = {0xFF,0xFF,0xFF,0xFF, 0x00,0xFF,0xFF,0x81, 0xFF,0xFF,0xFF,0xFF, 0x00,0xFF,0xFF,0x81};
303 store_u8_16(output, or_u8_16(load_u8_16(a), load_u8_16(b)));
308 uint8_t a[16] = {0xFF,0x0F,0xF0,0xAA, 0xFF,0x00,0xAB,0x01, 0xFF,0x0F,0xF0,0xAA, 0xFF,0x00,0xAB,0x01};
309 uint8_t b[16] = {0x0F,0xFF,0xFF,0x55, 0xFF,0x00,0xAB,0x01, 0x0F,0xFF,0xFF,0x55, 0xFF,0x00,0xAB,0x01};
310 uint8_t expected[16] = {0xF0,0xF0,0x0F,0xFF, 0x00,0x00,0x00,0x00, 0xF0,0xF0,0x0F,0xFF, 0x00,0x00,0x00,0x00};
312 store_u8_16(output, xor_u8_16(load_u8_16(a), load_u8_16(b)));
318 uint8_t a[16] = {0xFF,0x0F,0xF0,0xAA, 0x00,0xFF,0x55,0x80, 0xFF,0x0F,0xF0,0xAA, 0x00,0xFF,0x55,0x80};
319 uint8_t b[16] = {0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF};
320 uint8_t expected[16] = {0x00,0xF0,0x0F,0x55, 0xFF,0x00,0xAA,0x7F, 0x00,0xF0,0x0F,0x55, 0xFF,0x00,0xAA,0x7F};
322 store_u8_16(output, andnot_u8_16(load_u8_16(a), load_u8_16(b)));
332 store_u32_4(output, set1_u32_4(0xDEADBEEF));
339 store_u32_4(output, set1_u32_4(0));
346 store_u32_4(output, set_u32_4(0x11111111, 0x22222222, 0x33333333, 0x44444444));
352 float output[4] = {0.0f};
353 store_f32_4(output, set1_f32_4(3.14f));
354 float expected[4] = {3.14f, 3.14f, 3.14f, 3.14f};
364 if (extract_u32_4(v, 0) != 10)
return false;
365 if (extract_u32_4(v, 1) != 20)
return false;
366 if (extract_u32_4(v, 2) != 30)
return false;
367 if (extract_u32_4(v, 3) != 40)
return false;
376 uint32_t a[4] = {0xFFFFFFFF, 0x0F0F0F0F, 0xAAAAAAAA, 0x12345678};
377 uint32_t b[4] = {0x0F0F0F0F, 0xFFFFFFFF, 0x55555555, 0x12345678};
380 store_u32_4(output, xor_u32_4(load_u32_4(a), load_u32_4(b)));
385 uint32_t a[4] = {0xFFFF0000, 0x0F0F0F0F, 0xAAAAAAAA, 0x00000000};
386 uint32_t b[4] = {0x0000FFFF, 0xF0F0F0F0, 0xFFFFFFFF, 0xFFFFFFFF};
389 store_u32_4(output, and_u32_4(load_u32_4(a), load_u32_4(b)));
394 uint32_t a[4] = {0xFFFF0000, 0x0F0F0F0F, 0xAAAAAAAA, 0x00000000};
395 uint32_t b[4] = {0x0000FFFF, 0xF0F0F0F0, 0x55555555, 0x00000000};
398 store_u32_4(output, or_u32_4(load_u32_4(a), load_u32_4(b)));
411 store_u32_4(output, add_i32_4(load_u32_4(a), load_u32_4(b)));
412 if (
as_i32(output[0]) != 300)
return false;
413 if (
as_i32(output[1]) != -300)
return false;
415 if (output[2] != 0x80000000)
return false;
416 if (
as_i32(output[3]) != 0)
return false;
424 store_u32_4(output, sub_i32_4(load_u32_4(a), load_u32_4(b)));
425 if (
as_i32(output[0]) != 100)
return false;
426 if (
as_i32(output[1]) != -300)
return false;
427 if (
as_i32(output[2]) != 0)
return false;
428 if (
as_i32(output[3]) != 0)
return false;
437 uint32_t input[4] = {0x80000000, 0xFFFFFFFF, 0x00000010, 0x12345678};
439 store_u32_4(output, srl_u32_4(load_u32_4(input), 4));
445 uint32_t input[4] = {0x00000001, 0x0FFFFFFF, 0x80000000, 0x12345678};
447 store_u32_4(output, sll_u32_4(load_u32_4(input), 4));
456 store_u32_4(output, sra_i32_4(load_u32_4(input), 2));
457 if (
as_i32(output[0]) != -4)
return false;
458 if (
as_i32(output[1]) != 4)
return false;
459 if (
as_i32(output[2]) !=
as_i32(0xE0000000))
return false;
460 if (
as_i32(output[3]) !=
as_i32(0x1FFFFFFF))
return false;
472 store_u32_4(output, min_i32_4(load_u32_4(a), load_u32_4(b)));
473 if (
as_i32(output[0]) != 10)
return false;
474 if (
as_i32(output[1]) != -10)
return false;
476 if (
as_i32(output[3]) != -1)
return false;
484 store_u32_4(output, max_i32_4(load_u32_4(a), load_u32_4(b)));
485 if (
as_i32(output[0]) != 20)
return false;
486 if (
as_i32(output[1]) != 10)
return false;
487 if (
as_i32(output[2]) != 0x7FFFFFFF)
return false;
488 if (
as_i32(output[3]) != 0)
return false;
499 uint32_t a[4] = {0x00010000, 0x00020000,
as_u32(-0x00010000), 0x00008000};
500 uint32_t b[4] = {0x00020000, 0x00010000, 0x00020000, 0x00008000};
502 store_u32_4(output, mulhi_i32_4(load_u32_4(a), load_u32_4(b)));
503 if (output[0] != 0x00020000)
return false;
504 if (output[1] != 0x00020000)
return false;
505 if (
as_i32(output[2]) != -0x00020000)
return false;
506 if (output[3] != 0x00004000)
return false;
512 uint32_t a[4] = {0x00010000, 0x00020000, 0x00030000, 0x00008000};
513 uint32_t b[4] = {0x00020000, 0x00030000, 0x00010000, 0x00008000};
515 store_u32_4(output, mulhi_u32_4(load_u32_4(a), load_u32_4(b)));
516 if (output[0] != 0x00020000)
return false;
517 if (output[1] != 0x00060000)
return false;
518 if (output[2] != 0x00030000)
return false;
519 if (output[3] != 0x00004000)
return false;
527 uint32_t b[4] = {0x00020000, 0x00010000, 0x00010000, 0x00030000};
529 store_u32_4(output, mulhi_su32_4(load_u32_4(a), load_u32_4(b)));
530 if (
as_i32(output[0]) != -0x00020000)
return false;
531 if (output[1] != 0x00020000)
return false;
532 if (
as_i32(output[2]) != -0x00020000)
return false;
533 if (output[3] != 0x00030000)
return false;
540 uint32_t a[4] = {0x40000000,
as_u32(-0x40000000), 0x7FFFFFFF, 0x00000001};
541 uint32_t b[4] = {0x40000000, 0x40000000, 0x00000002, 0x7FFFFFFF};
543 store_u32_4(output, mulhi32_i32_4(load_u32_4(a), load_u32_4(b)));
544 if (output[0] != 0x10000000)
return false;
545 if (
as_i32(output[1]) !=
as_i32(0xF0000000))
return false;
546 if (output[2] != 0x00000000)
return false;
547 if (output[3] != 0x00000000)
return false;
560 store_u32_4(output, unpacklo_u32_4(a, b));
570 store_u32_4(output, unpackhi_u32_4(a, b));
580 store_u32_4(output, unpacklo_u64_as_u32_4(a, b));
590 store_u32_4(output, unpackhi_u64_as_u32_4(a, b));
600 float a[4] = {1.0f, 2.0f, 3.0f, 4.0f};
601 float b[4] = {5.0f, 6.0f, 7.0f, 8.0f};
602 float expected[4] = {6.0f, 8.0f, 10.0f, 12.0f};
603 float output[4] = {0.0f};
604 store_f32_4(output, add_f32_4(load_f32_4(a), load_f32_4(b)));
609 float a[4] = {-1.0f, 2.0f, -3.0f, 0.0f};
610 float b[4] = {1.0f, -2.0f, -3.0f, 0.0f};
611 float expected[4] = {0.0f, 0.0f, -6.0f, 0.0f};
612 float output[4] = {0.0f};
613 store_f32_4(output, add_f32_4(load_f32_4(a), load_f32_4(b)));
618 float a[4] = {10.0f, 20.0f, 30.0f, 40.0f};
619 float b[4] = {1.0f, 2.0f, 3.0f, 4.0f};
620 float expected[4] = {9.0f, 18.0f, 27.0f, 36.0f};
621 float output[4] = {0.0f};
622 store_f32_4(output, sub_f32_4(load_f32_4(a), load_f32_4(b)));
627 float a[4] = {2.0f, 3.0f, 4.0f, 5.0f};
628 float b[4] = {3.0f, 4.0f, 5.0f, 6.0f};
629 float expected[4] = {6.0f, 12.0f, 20.0f, 30.0f};
630 float output[4] = {0.0f};
631 store_f32_4(output, mul_f32_4(load_f32_4(a), load_f32_4(b)));
636 float a[4] = {-2.0f, 3.0f, -4.0f, 0.0f};
637 float b[4] = {3.0f, -4.0f, -5.0f, 100.0f};
638 float expected[4] = {-6.0f, -12.0f, 20.0f, 0.0f};
639 float output[4] = {0.0f};
640 store_f32_4(output, mul_f32_4(load_f32_4(a), load_f32_4(b)));
645 float a[4] = {10.0f, 20.0f, 30.0f, 40.0f};
646 float b[4] = {2.0f, 4.0f, 5.0f, 8.0f};
647 float expected[4] = {5.0f, 5.0f, 6.0f, 5.0f};
648 float output[4] = {0.0f};
649 store_f32_4(output, div_f32_4(load_f32_4(a), load_f32_4(b)));
654 float a[4] = {4.0f, 9.0f, 16.0f, 25.0f};
655 float expected[4] = {2.0f, 3.0f, 4.0f, 5.0f};
656 float output[4] = {0.0f};
657 store_f32_4(output, sqrt_f32_4(load_f32_4(a)));
662 float a[4] = {0.0f, 1.0f, 100.0f, 0.25f};
663 float expected[4] = {0.0f, 1.0f, 10.0f, 0.5f};
664 float output[4] = {0.0f};
665 store_f32_4(output, sqrt_f32_4(load_f32_4(a)));
670 float a[4] = {1.0f, 5.0f, -3.0f, 7.0f};
671 float b[4] = {4.0f, 2.0f, 6.0f, -1.0f};
672 float expected[4] = {1.0f, 2.0f, -3.0f, -1.0f};
673 float output[4] = {0.0f};
674 store_f32_4(output, min_f32_4(load_f32_4(a), load_f32_4(b)));
679 float a[4] = {1.0f, 5.0f, -3.0f, 7.0f};
680 float b[4] = {4.0f, 2.0f, 6.0f, -1.0f};
681 float expected[4] = {4.0f, 5.0f, 6.0f, 7.0f};
682 float output[4] = {0.0f};
683 store_f32_4(output, max_f32_4(load_f32_4(a), load_f32_4(b)));
696 for (
int i = 0; i < 16; i++) out[i] = a[i] & b[i];
699 for (
int i = 0; i < 16; i++) out[i] = a[i] | b[i];
702 for (
int i = 0; i < 16; i++) out[i] = a[i] ^ b[i];
705 for (
int i = 0; i < 16; i++) out[i] = (~a[i]) & b[i];
708 for (
int i = 0; i < 4; i++) out[i] = a[i] ^ b[i];
711 for (
int i = 0; i < 4; i++) out[i] = a[i] & b[i];
714 for (
int i = 0; i < 4; i++) out[i] = a[i] | b[i];
719 uint8_t a[16] = {0xAA,0x55,0xFF,0x00, 0x0F,0xF0,0x81,0x7E, 0x01,0xFE,0xCC,0x33, 0xDB,0x24,0xA5,0x5A};
720 uint8_t b[16] = {0x55,0xAA,0x00,0xFF, 0xF0,0x0F,0x7E,0x81, 0xFE,0x01,0x33,0xCC, 0x24,0xDB,0x5A,0xA5};
723 store_u8_16(actual, and_u8_16(load_u8_16(a), load_u8_16(b)));
728 uint8_t a[16] = {0xAA,0x55,0xFF,0x00, 0x0F,0xF0,0x81,0x7E, 0x01,0xFE,0xCC,0x33, 0xDB,0x24,0xA5,0x5A};
729 uint8_t b[16] = {0x55,0xAA,0x00,0xFF, 0xF0,0x0F,0x7E,0x81, 0xFE,0x01,0x33,0xCC, 0x24,0xDB,0x5A,0xA5};
732 store_u8_16(actual, or_u8_16(load_u8_16(a), load_u8_16(b)));
737 uint8_t a[16] = {0xAA,0x55,0xFF,0x00, 0x0F,0xF0,0x81,0x7E, 0x01,0xFE,0xCC,0x33, 0xDB,0x24,0xA5,0x5A};
738 uint8_t b[16] = {0x55,0xAA,0x00,0xFF, 0xF0,0x0F,0x7E,0x81, 0xFE,0x01,0x33,0xCC, 0x24,0xDB,0x5A,0xA5};
741 store_u8_16(actual, xor_u8_16(load_u8_16(a), load_u8_16(b)));
746 uint8_t a[16] = {0xAA,0x55,0xFF,0x00, 0x0F,0xF0,0x81,0x7E, 0x01,0xFE,0xCC,0x33, 0xDB,0x24,0xA5,0x5A};
747 uint8_t b[16] = {0x55,0xAA,0x00,0xFF, 0xF0,0x0F,0x7E,0x81, 0xFE,0x01,0x33,0xCC, 0x24,0xDB,0x5A,0xA5};
750 store_u8_16(actual, andnot_u8_16(load_u8_16(a), load_u8_16(b)));
756 uint32_t a[4] = {0x80000001, 0x7FFFFFFE, 0xDEADBEEF, 0x00000000};
757 uint32_t b[4] = {0x80000001, 0x80000001, 0xCAFEBABE, 0xFFFFFFFF};
760 store_u32_4(actual, xor_u32_4(load_u32_4(a), load_u32_4(b)));
765 uint32_t a[4] = {0x80000001, 0x7FFFFFFE, 0xDEADBEEF, 0x00000000};
766 uint32_t b[4] = {0x80000001, 0x80000001, 0xCAFEBABE, 0xFFFFFFFF};
769 store_u32_4(actual, and_u32_4(load_u32_4(a), load_u32_4(b)));
774 uint32_t a[4] = {0x80000001, 0x7FFFFFFE, 0xDEADBEEF, 0x00000000};
775 uint32_t b[4] = {0x80000001, 0x80000001, 0xCAFEBABE, 0xFFFFFFFF};
778 store_u32_4(actual, or_u32_4(load_u32_4(a), load_u32_4(b)));
784 for (
int i = 0; i < 16; i++) {
791 uint8_t v[16] = {0,1,127,128, 254,255,0x55,0xAA, 0x0F,0xF0,0x80,0x7F, 0x01,0xFE,0xFF,0x00};
792 uint8_t scale_vals[] = {0, 1, 127, 128, 254, 255};
793 for (
int s = 0; s < 6; s++) {
796 store_u8_16(actual, scale_u8_16(load_u8_16(v), scale_vals[s]));
804 for (
int i = 0; i < 16; i++) {
806 out[i] = (sum > 255) ? 255 : (
uint8_t)sum;
810 for (
int i = 0; i < 16; i++) {
811 out[i] = (a[i] > b[i]) ? (a[i] - b[i]) : 0;
818 uint8_t a[16] = {255,254,128,127, 0,1,200,50, 0xFF,0x80,0x7F,0x01, 100,200,150,250};
819 uint8_t b[16] = {255,2,128,129, 0,255,56,206, 0x01,0x80,0x81,0xFF, 156,56,106,6};
822 store_u8_16(actual, add_sat_u8_16(load_u8_16(a), load_u8_16(b)));
827 uint8_t a[16] = {255,0,128,127, 0,1,200,50, 0xFF,0x80,0x7F,0x01, 100,200,150,250};
828 uint8_t b[16] = {255,255,128,129, 0,255,56,206, 0x01,0x80,0x81,0xFF, 156,56,106,6};
831 store_u8_16(actual, sub_sat_u8_16(load_u8_16(a), load_u8_16(b)));
837 for (
int i = 0; i < 4; i++) out[i] = a[i] + b[i];
840 for (
int i = 0; i < 4; i++) out[i] = a[i] - b[i];
845 uint32_t a[4] = {0x7FFFFFFF, 0x80000000, 0xFFFFFFFF, 0x00000001};
846 uint32_t b[4] = {0x00000001, 0x80000000, 0x00000001, 0xFFFFFFFF};
849 store_u32_4(actual, add_i32_4(load_u32_4(a), load_u32_4(b)));
854 uint32_t a[4] = {0x00000000, 0x80000000, 0x7FFFFFFF, 0x00000001};
855 uint32_t b[4] = {0x00000001, 0x7FFFFFFF, 0x80000000, 0x00000002};
858 store_u32_4(actual, sub_i32_4(load_u32_4(a), load_u32_4(b)));
864 for (
int i = 0; i < 4; i++) out[i] = v[i] >> shift;
867 for (
int i = 0; i < 4; i++) out[i] = v[i] << shift;
870 for (
int i = 0; i < 4; i++) out[i] = (
uint32_t)((
int32_t)v[i] >> shift);
874 uint32_t v[4] = {0x80000000, 0xFFFFFFFF, 0x00000001, 0xDEADBEEF};
875 for (
int shift = 0; shift <= 31; shift += 7) {
878 store_u32_4(actual, srl_u32_4(load_u32_4(v), shift));
885 uint32_t v[4] = {0x80000000, 0xFFFFFFFF, 0x00000001, 0xDEADBEEF};
886 for (
int shift = 0; shift <= 31; shift += 7) {
889 store_u32_4(actual, sll_u32_4(load_u32_4(v), shift));
896 uint32_t v[4] = {0x80000000, 0xFFFFFFFF, 0x7FFFFFFF, 0xDEADBEEF};
897 for (
int shift = 0; shift <= 31; shift += 7) {
900 store_u32_4(actual, sra_i32_4(load_u32_4(v), shift));
908 for (
int i = 0; i < 4; i++) {
910 out[i] = (
uint32_t)(ai < bi ? ai : bi);
914 for (
int i = 0; i < 4; i++) {
916 out[i] = (
uint32_t)(ai > bi ? ai : bi);
921 uint32_t a[4] = {0x80000000, 0x7FFFFFFF, 0xFFFFFFFF, 0x00000000};
922 uint32_t b[4] = {0x7FFFFFFF, 0x80000000, 0x00000000, 0xFFFFFFFF};
925 store_u32_4(actual, min_i32_4(load_u32_4(a), load_u32_4(b)));
930 uint32_t a[4] = {0x80000000, 0x7FFFFFFF, 0xFFFFFFFF, 0x00000000};
931 uint32_t b[4] = {0x7FFFFFFF, 0x80000000, 0x00000000, 0xFFFFFFFF};
934 store_u32_4(actual, max_i32_4(load_u32_4(a), load_u32_4(b)));
940 for (
int i = 0; i < 4; i++) {
946 for (
int i = 0; i < 4; i++) {
947 uint64_t prod = (uint64_t)a[i] * (uint64_t)b[i];
952 for (
int i = 0; i < 4; i++) {
959 uint32_t a[4] = {0x7FFFFFFF, 0x80000000, 0x00010000, 0xFFFF0000};
960 uint32_t b[4] = {0x00020000, 0x00020000, 0xFFFF0000, 0xFFFF0000};
963 store_u32_4(actual, mulhi_i32_4(load_u32_4(a), load_u32_4(b)));
968 uint32_t a[4] = {0xFFFFFFFF, 0x80000000, 0x00010000, 0x00000001};
969 uint32_t b[4] = {0x00000002, 0x00000002, 0x00010000, 0xFFFFFFFF};
972 store_u32_4(actual, mulhi_u32_4(load_u32_4(a), load_u32_4(b)));
977 uint32_t a[4] = {0x7FFFFFFF, 0x80000000, 0x40000000, 0xC0000000};
978 uint32_t b[4] = {0x7FFFFFFF, 0x80000000, 0x40000000, 0x40000000};
981 store_u32_4(actual, mulhi32_i32_4(load_u32_4(a), load_u32_4(b)));
987 for (
int i = 0; i < 16; i++) out[i] = a[i] < b[i] ? a[i] : b[i];
990 for (
int i = 0; i < 16; i++) out[i] = a[i] > b[i] ? a[i] : b[i];
994 uint8_t a[16] = {0,255,128,127, 1,254,0x55,0xAA, 0x0F,0xF0,0x80,0x7F, 0x01,0xFE,0xFF,0x00};
995 uint8_t b[16] = {255,0,127,128, 254,1,0xAA,0x55, 0xF0,0x0F,0x7F,0x80, 0xFE,0x01,0x00,0xFF};
998 store_u8_16(actual, min_u8_16(load_u8_16(a), load_u8_16(b)));
1003 uint8_t a[16] = {0,255,128,127, 1,254,0x55,0xAA, 0x0F,0xF0,0x80,0x7F, 0x01,0xFE,0xFF,0x00};
1004 uint8_t b[16] = {255,0,127,128, 254,1,0xAA,0x55, 0xF0,0x0F,0x7F,0x80, 0xFE,0x01,0x00,0xFF};
1007 store_u8_16(actual, max_u8_16(load_u8_16(a), load_u8_16(b)));
1013 float a[4] = {-1.5f, 0.0f, 3.14159f, 1e10f};
1014 float b[4] = {2.5f, -0.0f, -2.71828f, 1e-10f};
1017 store_f32_4(out, add_f32_4(load_f32_4(a), load_f32_4(b)));
1018 for (
int i = 0; i < 4; i++) {
1019 float diff = out[i] - (a[i] + b[i]);
1020 if (diff < -0.001f || diff > 0.001f)
return false;
1023 store_f32_4(out, sub_f32_4(load_f32_4(a), load_f32_4(b)));
1024 for (
int i = 0; i < 4; i++) {
1025 float diff = out[i] - (a[i] - b[i]);
1026 if (diff < -0.001f || diff > 0.001f)
return false;
1029 store_f32_4(out, mul_f32_4(load_f32_4(a), load_f32_4(b)));
1030 for (
int i = 0; i < 4; i++) {
1031 float diff = out[i] - (a[i] * b[i]);
1032 if (diff < -1.0f && diff > 1.0f)
return false;
1042 store_u32_4_aligned(dst, v);
1049 uint32_t test_values[] = {0x80000000, 0xFFFFFFFF, 0x00000000, 0xAAAAAAAA, 0x55555555, 0x01010101};
1050 for (
int t = 0;
t < 6;
t++) {
1053 store_u32_4(output, set1_u32_4(val));
1054 for (
int i = 0; i < 4; i++) {
1055 if (output[i] != val)
return false;
1067 uint8_t input[16] = {200,200,200,200, 200,200,200,200, 200,200,200,200, 200,200,200,200};
1068 uint8_t bias[16] = {200,200,200,200, 200,200,200,200, 200,200,200,200, 200,200,200,200};
1071 v = scale_u8_16(v, 128);
1072 v = add_sat_u8_16(v, load_u8_16(bias));
1073 store_u8_16(output, v);
1074 for (
int i = 0; i < 16; i++) {
1075 if (output[i] < 250)
return false;
1082 uint32_t angles[4] = {0x10000000, 0x20000000, 0x30000000, 0x40000000};
1084 v = srl_u32_4(v, 16);
1085 v = add_i32_4(v, set1_u32_4(0x100));
1086 v = and_u32_4(v, set1_u32_4(0xFFFF));
1088 store_u32_4(output, v);
1095 float input[4] = {0.3f, 0.6f, 0.9f, 1.2f};
1096 float gain[4] = {2.0f, 2.0f, 2.0f, 2.0f};
1097 float output[4] = {0.0f};
1099 v = mul_f32_4(v, load_f32_4(gain));
1100 v = min_f32_4(v, set1_f32_4(1.0f));
1101 v = max_f32_4(v, set1_f32_4(0.0f));
1102 store_f32_4(output, v);
1103 float expected[4] = {0.6f, 1.0f, 1.0f, 1.0f};
1134template <
typename Op>
1136 float a0 = 1.5f, a1 = 2.3f, a2 = 0.7f, a3 = 3.1f;
1137 float b0 = 0.5f, b1 = 1.2f, b2 = 2.0f, b3 = 0.9f;
1139 for (
int i = 0; i < iters; i++) {
1140 a0 = op(a0, b0); a1 = op(a1, b1);
1141 a2 = op(a2, b2); a3 = op(a3, b3);
1142 b0 = a0 + 0.001f; b1 = a1 + 0.001f;
1143 b2 = a2 + 0.001f; b3 = a3 + 0.001f;
1148 return static_cast<int64_t
>(t1 - t0);
1152template <
typename Op>
1154 fl::s16x16 a0(1.5f), a1(2.3f), a2(0.7f), a3(3.1f);
1155 fl::s16x16 b0(0.5f), b1(1.2f), b2(2.0f), b3(0.9f);
1158 for (
int i = 0; i < iters; i++) {
1159 a0 = op(a0, b0); a1 = op(a1, b1);
1160 a2 = op(a2, b2); a3 = op(a3, b3);
1161 b0 = a0 + bump; b1 = a1 + bump;
1162 b2 = a2 + bump; b3 = a3 + bump;
1166 return static_cast<int64_t
>(t1 - t0);
1170template <
typename Op>
1180 for (
int i = 0; i < iters; i++) {
1186 return static_cast<int64_t
>(t1 - t0);
1190 template<
typename T> T
operator()(T a, T b)
const {
return a + b; }
1193 template<
typename T> T
operator()(T a, T b)
const {
return a - b; }
1196 template<
typename T> T
operator()(T a, T b)
const {
return a * b; }
1199template <
typename Op>
1201 fl::s8x8 a0(1.5f), a1(2.3f), a2(0.7f), a3(3.1f);
1202 fl::s8x8 b0(0.5f), b1(1.2f), b2(2.0f), b3(0.9f);
1205 for (
int i = 0; i < iters; i++) {
1206 a0 = op(a0, b0); a1 = op(a1, b1);
1207 a2 = op(a2, b2); a3 = op(a3, b3);
1208 b0 = a0 + bump; b1 = a1 + bump;
1209 b2 = a2 + bump; b3 = a3 + bump;
1213 return static_cast<int64_t
>(t1 - t0);
1217template <
typename Op>
1219 fl::u16x16 a0(1.5f), a1(2.3f), a2(0.7f), a3(3.1f);
1220 fl::u16x16 b0(0.5f), b1(1.2f), b2(2.0f), b3(0.9f);
1223 for (
int i = 0; i < iters; i++) {
1224 a0 = op(a0, b0); a1 = op(a1, b1);
1225 a2 = op(a2, b2); a3 = op(a3, b3);
1226 b0 = a0 + bump; b1 = a1 + bump;
1227 b2 = a2 + bump; b3 = a3 + bump;
1231 return static_cast<int64_t
>(t1 - t0);
1399 *out_count =
sizeof(tests) /
sizeof(tests[0]);
1412 FL_PRINT(
"────────────────────────────────────────────────────────────────");
1414#if defined(__x86_64__) || defined(_M_X64) || defined(__i386__) || defined(_M_IX86)
1415 FL_PRINT(
" SIMD Backend: x86 SSE2");
1416#elif defined(__XTENSA__) && FL_XTENSA_HAS_PIE
1417 FL_PRINT(
" SIMD Backend: Xtensa PIE (ESP32-S3)");
1418#elif defined(__XTENSA__)
1419 FL_PRINT(
" SIMD Backend: Xtensa scalar");
1420#elif defined(__riscv)
1421 FL_PRINT(
" SIMD Backend: RISC-V scalar");
1423 FL_PRINT(
" SIMD Backend: Scalar fallback");
1427 ss <<
" Running " << num_tests <<
" SIMD tests...\n";
1430 for (
int i = 0; i < num_tests; i++) {
1431 bool ok = tests[i].
func();
1435 ss <<
" [PASS] " << tests[i].
name;
1440 ss <<
" [FAIL] " << tests[i].
name;
1446 ss <<
"\n[SIMD RESULTS] " << passed <<
"/" << num_tests <<
" passed";
1448 ss <<
", " << failed <<
" FAILED";
1451 ss <<
" - ALL PASSED";
fl::UISlider scale("Scale", 4,.1, 4,.1)
FastLED chrono implementation - duration types for time measurements.
static T & instance() FL_NO_EXCEPT
expected type for operations that can fail (C++23-style)
static constexpr FASTLED_FORCE_INLINE s16x16 from_raw(i32 raw) FL_NO_EXCEPT
static constexpr FASTLED_FORCE_INLINE s8x8 from_raw(i16 raw) FL_NO_EXCEPT
void clear() FL_NO_EXCEPT
string str() const FL_NO_EXCEPT
static constexpr FASTLED_FORCE_INLINE u16x16 from_raw(u32 raw) FL_NO_EXCEPT
uint32_t as_u32(int32_t v)
void ref_srl_u32_4(const uint32_t *v, int shift, uint32_t *out)
bool test_mulhi32_i32_4()
bool test_extract_u32_4()
bool test_sqrt_f32_4_zero()
bool test_crossval_mulhi_u32_4()
void ref_and_u32_4(const uint32_t *a, const uint32_t *b, uint32_t *out)
bool test_crossval_max_u8_16()
bool test_u8_pipeline_scale_add_clamp()
bool test_unpacklo_u64_as_u32_4()
void ref_add_sat_u8_16(const uint8_t *a, const uint8_t *b, uint8_t *out)
bool test_add_sat_u8_16()
bool test_crossval_and_u32_4()
int64_t benchSimd4(int iters, Op op)
bool test_crossval_scale_u8_16()
bool compare_u32(const uint32_t *a, const uint32_t *b, size_t n)
int64_t benchS16x16_4(int iters, Op op)
SimdBenchmarkState & simdBenchmarkState()
void ref_max_u8_16(const uint8_t *a, const uint8_t *b, uint8_t *out)
bool test_crossval_sub_i32_4()
void ref_max_i32_4(const uint32_t *a, const uint32_t *b, uint32_t *out)
bool test_load_store_u32_4_boundary()
bool test_i32_pipeline_shift_add_mask()
bool test_crossval_xor_u32_4()
bool test_crossval_aligned_load_store()
bool test_scale_u8_16_zero()
bool test_crossval_mulhi32_i32_4()
int64_t benchFloat4(int iters, Op op)
bool test_crossval_set1_u32_4()
void ref_scale_u8_16(const uint8_t *v, uint8_t scale, uint8_t *out)
bool test_crossval_sll_u32_4()
int runSimdTests()
Run the full SIMD test suite. Returns the number of failures.
bool test_unpackhi_u64_as_u32_4()
void ref_xor_u8_16(const uint8_t *a, const uint8_t *b, uint8_t *out)
bool test_blend_u8_16_endpoints()
bool test_mul_f32_4_negative()
int64_t benchS8x8_4(int iters, Op op)
bool test_crossval_srl_u32_4()
void ref_andnot_u8_16(const uint8_t *a, const uint8_t *b, uint8_t *out)
bool test_crossval_add_sat_u8_16()
void ref_mulhi_i32_4(const uint32_t *a, const uint32_t *b, uint32_t *out)
void ref_sll_u32_4(const uint32_t *v, int shift, uint32_t *out)
int32_t as_i32(uint32_t v)
void ref_and_u8_16(const uint8_t *a, const uint8_t *b, uint8_t *out)
bool test_load_store_f32_4()
bool test_crossval_or_u8_16()
bool test_load_store_f32_4_special()
bool test_crossval_add_i32_4()
bool test_unpackhi_u32_4()
bool test_scale_u8_16_full()
void getTests(const SimdTestEntry **out_tests, int *out_count)
Get the static test table. Used by both runSimdTests() and the RPC handler.
bool test_load_store_u8_16_boundary()
void ref_or_u32_4(const uint32_t *a, const uint32_t *b, uint32_t *out)
bool test_crossval_sub_sat_u8_16()
void ref_min_i32_4(const uint32_t *a, const uint32_t *b, uint32_t *out)
void ref_add_i32_4(const uint32_t *a, const uint32_t *b, uint32_t *out)
bool test_unpacklo_u32_4()
bool test_crossval_float_ops()
void ref_or_u8_16(const uint8_t *a, const uint8_t *b, uint8_t *out)
void ref_sub_i32_4(const uint32_t *a, const uint32_t *b, uint32_t *out)
bool test_load_store_u32_4()
bool test_load_store_u32_4_aligned()
bool test_crossval_or_u32_4()
bool compare_u8(const uint8_t *a, const uint8_t *b, size_t n)
bool test_crossval_sra_i32_4()
bool test_crossval_andnot_u8_16()
void ref_xor_u32_4(const uint32_t *a, const uint32_t *b, uint32_t *out)
void ref_sra_i32_4(const uint32_t *v, int shift, uint32_t *out)
void ref_min_u8_16(const uint8_t *a, const uint8_t *b, uint8_t *out)
bool test_crossval_and_u8_16()
int64_t benchU16x16_4(int iters, Op op)
bool compare_f32(const float *a, const float *b, size_t n, float eps=0.001f)
BenchmarkResult runMultiplyBenchmark(int iters=10000)
bool test_sub_sat_u8_16_full_clamp()
bool test_f32_pipeline_mul_add_clamp()
void ref_mulhi_u32_4(const uint32_t *a, const uint32_t *b, uint32_t *out)
bool test_avg_round_u8_16()
void ref_mulhi32_i32_4(const uint32_t *a, const uint32_t *b, uint32_t *out)
bool test_add_f32_4_negative()
bool test_load_store_u8_16()
bool test_set1_u32_4_zero()
void ref_sub_sat_u8_16(const uint8_t *a, const uint8_t *b, uint8_t *out)
bool test_crossval_xor_u8_16()
bool test_crossval_mulhi_i32_4()
bool test_add_sat_u8_16_full_saturate()
bool test_crossval_max_i32_4()
bool test_crossval_min_u8_16()
bool test_crossval_min_i32_4()
bool test_sub_sat_u8_16()
platforms::simd_u32x4 simd_u32x4
platforms::simd_u8x16 simd_u8x16
platforms::simd_f32x4 simd_f32x4
fl::u32 micros() FL_NO_EXCEPT
Universal microsecond timer - returns microseconds since system startup.
FASTLED_FORCE_INLINE void * memcpy(void *dest, const void *src, size_t n) FL_NO_EXCEPT
SIMD 4-wide s0x32 fixed-point vector type.
SIMD 4-wide s16x16 fixed-point vector type.
Umbrella header for SIMD subsystem.
T operator()(T a, T b) const
float operator()(float a, float b) const
fl::s16x16 operator()(fl::s16x16 a, fl::s16x16 b) const
fl::s8x8 operator()(fl::s8x8 a, fl::s8x8 b) const
fl::u16x16 operator()(fl::u16x16 a, fl::u16x16 b) const
T operator()(T a, T b) const
T operator()(T a, T b) const
static FASTLED_FORCE_INLINE s16x16x4 from_raw(simd::simd_u32x4 r)
static FASTLED_FORCE_INLINE s16x16x4 set1(s16x16 value)
4-wide s16x16 vector (general fixed-point) Backed by 128-bit SIMD register (4× i32 in Q16 format)