@img/sharp-libvips-dev-wasm32 1.3.0-rc.5 → 1.3.0-rc.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. package/README.md +23 -23
  2. package/include/expat.h +14 -2
  3. package/include/expat_config.h +6 -3
  4. package/include/expat_external.h +3 -2
  5. package/include/glib-2.0/glib/gvarianttype.h +16 -16
  6. package/include/glib-2.0/glib/gversionmacros.h +13 -0
  7. package/include/hwy/aligned_allocator.h +44 -2
  8. package/include/hwy/auto_tune.h +22 -6
  9. package/include/hwy/base.h +60 -90
  10. package/include/hwy/bit_set.h +410 -0
  11. package/include/hwy/cache_control.h +3 -2
  12. package/include/hwy/detect_compiler_arch.h +134 -14
  13. package/include/hwy/detect_targets.h +82 -36
  14. package/include/hwy/highway.h +15 -0
  15. package/include/hwy/nanobenchmark.h +12 -3
  16. package/include/hwy/ops/arm_neon-inl.h +96 -25
  17. package/include/hwy/ops/arm_sve-inl.h +250 -95
  18. package/include/hwy/ops/emu128-inl.h +12 -7
  19. package/include/hwy/ops/generic_ops-inl.h +271 -131
  20. package/include/hwy/ops/loongarch_lasx-inl.h +31 -9
  21. package/include/hwy/ops/loongarch_lsx-inl.h +33 -12
  22. package/include/hwy/ops/ppc_vsx-inl.h +99 -19
  23. package/include/hwy/ops/rvv-inl.h +239 -130
  24. package/include/hwy/ops/scalar-inl.h +22 -7
  25. package/include/hwy/ops/set_macros-inl.h +163 -107
  26. package/include/hwy/ops/wasm_128-inl.h +13 -22
  27. package/include/hwy/ops/x86_128-inl.h +223 -120
  28. package/include/hwy/ops/x86_256-inl.h +70 -134
  29. package/include/hwy/ops/x86_512-inl.h +130 -134
  30. package/include/hwy/print-inl.h +2 -0
  31. package/include/hwy/profiler.h +355 -264
  32. package/include/hwy/robust_statistics.h +3 -1
  33. package/include/hwy/timer.h +44 -0
  34. package/include/lcms2.h +34 -4
  35. package/include/libexif/exif-utils.h +1 -1
  36. package/include/libheif/heif_sequences.h +12 -2
  37. package/include/libheif/heif_uncompressed.h +8 -0
  38. package/include/libpng16/png.h +7 -7
  39. package/include/libpng16/pngconf.h +1 -1
  40. package/include/libpng16/pnglibconf.h +1 -1
  41. package/include/png.h +7 -7
  42. package/include/pngconf.h +1 -1
  43. package/include/pnglibconf.h +1 -1
  44. package/include/tiffconf.h +9 -10
  45. package/include/tiffio.h +10 -9
  46. package/include/tiffvers.h +1 -1
  47. package/include/ultrahdr_api.h +5 -11
  48. package/lib/glib-2.0/include/glibconfig.h +1 -1
  49. package/lib/libaom.a +0 -0
  50. package/lib/libcgif.a +0 -0
  51. package/lib/libexif.a +0 -0
  52. package/lib/libexif.la +1 -1
  53. package/lib/libexpat.a +0 -0
  54. package/lib/libexpat.la +3 -3
  55. package/lib/libffi.a +0 -0
  56. package/lib/libgio-2.0.a +0 -0
  57. package/lib/libglib-2.0.a +0 -0
  58. package/lib/libgmodule-2.0.a +0 -0
  59. package/lib/libgobject-2.0.a +0 -0
  60. package/lib/libgthread-2.0.a +0 -0
  61. package/lib/libheif.a +0 -0
  62. package/lib/libhwy.a +0 -0
  63. package/lib/libimagequant.a +0 -0
  64. package/lib/libjpeg.a +0 -0
  65. package/lib/liblcms2.a +0 -0
  66. package/lib/libpng.a +0 -0
  67. package/lib/libpng.la +2 -2
  68. package/lib/libpng16.a +0 -0
  69. package/lib/libpng16.la +2 -2
  70. package/lib/libresvg.a +0 -0
  71. package/lib/libsharpyuv.a +0 -0
  72. package/lib/libtiff.a +0 -0
  73. package/lib/libuhdr.a +0 -0
  74. package/lib/libvips-cpp.a +0 -0
  75. package/lib/libvips.a +0 -0
  76. package/lib/libwebp.a +0 -0
  77. package/lib/libwebpdecoder.a +0 -0
  78. package/lib/libwebpdemux.a +0 -0
  79. package/lib/libwebpmux.a +0 -0
  80. package/lib/libz.a +0 -0
  81. package/lib/pkgconfig/expat.pc +1 -1
  82. package/lib/pkgconfig/gio-2.0.pc +1 -1
  83. package/lib/pkgconfig/glib-2.0.pc +1 -1
  84. package/lib/pkgconfig/gmodule-2.0.pc +1 -1
  85. package/lib/pkgconfig/gmodule-export-2.0.pc +1 -1
  86. package/lib/pkgconfig/gmodule-no-export-2.0.pc +1 -1
  87. package/lib/pkgconfig/gobject-2.0.pc +1 -1
  88. package/lib/pkgconfig/gthread-2.0.pc +1 -1
  89. package/lib/pkgconfig/lcms2.pc +1 -1
  90. package/lib/pkgconfig/libexif.pc +1 -1
  91. package/lib/pkgconfig/libhwy.pc +3 -4
  92. package/lib/pkgconfig/libpng.pc +1 -1
  93. package/lib/pkgconfig/libpng16.pc +1 -1
  94. package/lib/pkgconfig/libsharpyuv.pc +1 -1
  95. package/lib/pkgconfig/libtiff-4.pc +2 -2
  96. package/lib/pkgconfig/libwebp.pc +1 -1
  97. package/lib/pkgconfig/libwebpdecoder.pc +11 -0
  98. package/lib/pkgconfig/libwebpmux.pc +1 -1
  99. package/package.json +1 -1
  100. package/versions.json +10 -10
  101. package/lib/libsharpyuv.la +0 -41
  102. package/lib/libtiff.la +0 -41
  103. package/lib/libwebp.la +0 -41
  104. package/lib/libwebpdemux.la +0 -41
  105. package/lib/libwebpmux.la +0 -41
@@ -22,6 +22,7 @@
22
22
  // the generic implementation here if native ops are already defined.
23
23
 
24
24
  #include "hwy/base.h"
25
+ #include "hwy/detect_compiler_arch.h"
25
26
 
26
27
  // Define detail::Shuffle1230 etc, but only when viewing the current header;
27
28
  // normally this is included via highway.h, which includes ops/*.h.
@@ -245,6 +246,22 @@ HWY_API Mask<D> MaskFalse(D d) {
245
246
 
246
247
  #endif // HWY_NATIVE_MASK_FALSE
247
248
 
249
+ // ------------------------------ SetMask
250
+ #if (defined(HWY_NATIVE_SET_MASK) == defined(HWY_TARGET_TOGGLE))
251
+ #ifdef HWY_NATIVE_SET_MASK
252
+ #undef HWY_NATIVE_SET_MASK
253
+ #else
254
+ #define HWY_NATIVE_SET_MASK
255
+ #endif
256
+
257
+ template <class D>
258
+ HWY_API Mask<D> SetMask(D d, bool val) {
259
+ const Repartition<int32_t, decltype(d)> di32;
260
+ return MaskFromVec(ResizeBitCast(d, Set(di32, -static_cast<int32_t>(val))));
261
+ }
262
+
263
+ #endif // HWY_NATIVE_SET_MASK
264
+
248
265
  // ------------------------------ IfNegativeThenElseZero
249
266
  #if (defined(HWY_NATIVE_IF_NEG_THEN_ELSE_ZERO) == defined(HWY_TARGET_TOGGLE))
250
267
  #ifdef HWY_NATIVE_IF_NEG_THEN_ELSE_ZERO
@@ -466,11 +483,11 @@ HWY_API V RotateLeft(V v) {
466
483
  }
467
484
 
468
485
  // ------------------------------ InterleaveWholeLower/InterleaveWholeUpper
469
- #if (defined(HWY_NATIVE_INTERLEAVE_WHOLE) == defined(HWY_TARGET_TOGGLE))
470
- #ifdef HWY_NATIVE_INTERLEAVE_WHOLE
471
- #undef HWY_NATIVE_INTERLEAVE_WHOLE
486
+ #if (defined(HWY_TOGGLE_INTERLEAVE_WHOLE) == defined(HWY_TARGET_TOGGLE))
487
+ #ifdef HWY_TOGGLE_INTERLEAVE_WHOLE
488
+ #undef HWY_TOGGLE_INTERLEAVE_WHOLE
472
489
  #else
473
- #define HWY_NATIVE_INTERLEAVE_WHOLE
490
+ #define HWY_TOGGLE_INTERLEAVE_WHOLE
474
491
  #endif
475
492
 
476
493
  #if HWY_TARGET != HWY_SCALAR || HWY_IDE
@@ -497,7 +514,7 @@ HWY_API VFromD<D> InterleaveWholeUpper(D d, VFromD<D> a, VFromD<D> b) {
497
514
  // is implemented in wasm_256-inl.h.
498
515
  #endif // HWY_TARGET != HWY_SCALAR
499
516
 
500
- #endif // HWY_NATIVE_INTERLEAVE_WHOLE
517
+ #endif // HWY_TOGGLE_INTERLEAVE_WHOLE
501
518
 
502
519
  #if HWY_TARGET != HWY_SCALAR || HWY_IDE
503
520
  // The InterleaveWholeLower without the optional D parameter is generic for all
@@ -834,6 +851,38 @@ HWY_API MFromD<D> MaskedIsNaN(const M m, const V v) {
834
851
  }
835
852
  #endif // HWY_NATIVE_MASKED_COMP
836
853
 
854
+ // ------------------------------ Xor3
855
+
856
+ #if (defined(HWY_NATIVE_XOR3) == defined(HWY_TARGET_TOGGLE))
857
+ #ifdef HWY_NATIVE_XOR3
858
+ #undef HWY_NATIVE_XOR3
859
+ #else
860
+ #define HWY_NATIVE_XOR3
861
+ #endif
862
+
863
+ template <class V>
864
+ HWY_API V Xor3(V x1, V x2, V x3) {
865
+ return Xor(x1, Xor(x2, x3));
866
+ }
867
+
868
+ #endif // HWY_NATIVE_XOR3
869
+
870
+ // ------------------------------ XorAndNot
871
+
872
+ #if (defined(HWY_NATIVE_BCAX) == defined(HWY_TARGET_TOGGLE))
873
+ #ifdef HWY_NATIVE_BCAX
874
+ #undef HWY_NATIVE_BCAX
875
+ #else
876
+ #define HWY_NATIVE_BCAX
877
+ #endif
878
+
879
+ template <class V>
880
+ HWY_API V XorAndNot(const V x, const V a1, const V a2) {
881
+ return Xor(x, AndNot(a1, a2));
882
+ }
883
+
884
+ #endif // HWY_NATIVE_BCAX
885
+
837
886
  // ------------------------------ IfNegativeThenNegOrUndefIfZero
838
887
 
839
888
  #if (defined(HWY_NATIVE_INTEGER_IF_NEGATIVE_THEN_NEG) == \
@@ -1279,12 +1328,10 @@ HWY_API VFromD<RebindToSigned<DFromV<V>>> FloorInt(V v) {
1279
1328
  template <class V, HWY_IF_FLOAT_V(V)>
1280
1329
  HWY_API V MulByPow2(V v, VFromD<RebindToSigned<DFromV<V>>> exp) {
1281
1330
  const DFromV<decltype(v)> df;
1282
- const RebindToUnsigned<decltype(df)> du;
1283
1331
  const RebindToSigned<decltype(df)> di;
1284
1332
 
1285
1333
  using TF = TFromD<decltype(df)>;
1286
1334
  using TI = TFromD<decltype(di)>;
1287
- using TU = TFromD<decltype(du)>;
1288
1335
 
1289
1336
  using VF = VFromD<decltype(df)>;
1290
1337
  using VI = VFromD<decltype(di)>;
@@ -1306,85 +1353,43 @@ HWY_API V MulByPow2(V v, VFromD<RebindToSigned<DFromV<V>>> exp) {
1306
1353
  using TExpMinMax = TI;
1307
1354
  #endif
1308
1355
 
1309
- #if HWY_TARGET == HWY_EMU128 || HWY_TARGET == HWY_SCALAR
1310
- using TExpSatSub = TU;
1311
- #elif HWY_TARGET <= HWY_SSE2 || HWY_TARGET == HWY_WASM || \
1312
- HWY_TARGET == HWY_WASM_EMU256
1313
- using TExpSatSub = If<(sizeof(TF) == 4), uint8_t, uint16_t>;
1314
- #elif HWY_TARGET_IS_PPC
1315
- using TExpSatSub = If<(sizeof(TF) >= 4), uint32_t, TU>;
1316
- #else
1317
- using TExpSatSub = If<(sizeof(TF) == 4), uint8_t, TU>;
1318
- #endif
1319
-
1320
1356
  static_assert(kExpBias <= static_cast<TI>(LimitsMax<TExpMinMax>() / 3),
1321
1357
  "kExpBias <= LimitsMax<TExpMinMax>() / 3 must be true");
1322
1358
 
1323
1359
  const Repartition<TExpMinMax, decltype(df)> d_exp_min_max;
1324
- const Repartition<TExpSatSub, decltype(df)> d_sat_exp_sub;
1325
1360
 
1326
- constexpr int kNumOfExpBits = ExponentBits<TF>();
1327
1361
  constexpr int kNumOfMantBits = MantissaBits<TF>();
1328
1362
 
1329
- // The sign bit of BitCastScalar<TU>(a[i]) >> kNumOfMantBits can be zeroed out
1330
- // using SaturatedSub if kZeroOutSignUsingSatSub is true.
1331
-
1332
- // If kZeroOutSignUsingSatSub is true, then val_for_exp_sub will be bitcasted
1333
- // to a vector that has a smaller lane size than TU for the SaturatedSub
1334
- // operation below.
1335
- constexpr bool kZeroOutSignUsingSatSub =
1336
- ((sizeof(TExpSatSub) * 8) == static_cast<size_t>(kNumOfExpBits));
1337
-
1338
- // If kZeroOutSignUsingSatSub is true, then the upper
1339
- // (sizeof(TU) - sizeof(TExpSatSub)) * 8 bits of kExpDecrBy1Bits will be all
1340
- // ones and the lower sizeof(TExpSatSub) * 8 bits of kExpDecrBy1Bits will be
1341
- // equal to 1.
1342
-
1343
- // Otherwise, if kZeroOutSignUsingSatSub is false, kExpDecrBy1Bits will be
1344
- // equal to 1.
1345
- constexpr TU kExpDecrBy1Bits = static_cast<TU>(
1346
- TU{1} - (static_cast<TU>(kZeroOutSignUsingSatSub) << kNumOfExpBits));
1347
-
1348
- VF val_for_exp_sub = v;
1349
- HWY_IF_CONSTEXPR(!kZeroOutSignUsingSatSub) {
1350
- // If kZeroOutSignUsingSatSub is not true, zero out the sign bit of
1351
- // val_for_exp_sub[i] using Abs
1352
- val_for_exp_sub = Abs(val_for_exp_sub);
1353
- }
1354
-
1355
- // min_exp1_plus_min_exp2[i] is the smallest exponent such that
1356
- // min_exp1_plus_min_exp2[i] >= 2 - kExpBias * 2 and
1357
- // std::ldexp(v[i], min_exp1_plus_min_exp2[i]) is a normal floating-point
1358
- // number if v[i] is a normal number
1359
- const VI min_exp1_plus_min_exp2 = BitCast(
1360
- di,
1361
- Max(BitCast(
1362
- d_exp_min_max,
1363
- Neg(BitCast(
1364
- di,
1365
- SaturatedSub(
1366
- BitCast(d_sat_exp_sub, ShiftRight<kNumOfMantBits>(
1367
- BitCast(du, val_for_exp_sub))),
1368
- BitCast(d_sat_exp_sub, Set(du, kExpDecrBy1Bits)))))),
1369
- BitCast(d_exp_min_max,
1370
- Set(di, static_cast<TI>(2 - kExpBias - kExpBias)))));
1363
+ const VI exp_bias = Set(di, kExpBias);
1371
1364
 
1372
1365
  const VI clamped_exp =
1373
- Max(Min(exp, Set(di, static_cast<TI>(kExpBias * 3))),
1374
- Add(min_exp1_plus_min_exp2, Set(di, static_cast<TI>(1 - kExpBias))));
1366
+ Clamp(exp, Set(di, 3 - 3 * kExpBias), Set(di, 3 * kExpBias));
1375
1367
 
1376
- const VI exp1_plus_exp2 = BitCast(
1377
- di, Max(Min(BitCast(d_exp_min_max,
1378
- Sub(clamped_exp, ShiftRight<2>(clamped_exp))),
1379
- BitCast(d_exp_min_max,
1380
- Set(di, static_cast<TI>(kExpBias + kExpBias)))),
1381
- BitCast(d_exp_min_max, min_exp1_plus_min_exp2)));
1368
+ const auto min_scale_factor_exp =
1369
+ BitCast(d_exp_min_max, Set(di, 1 - kExpBias));
1370
+ const auto max_scale_factor_exp = BitCast(d_exp_min_max, exp_bias);
1382
1371
 
1383
- const VI exp1 = ShiftRight<1>(exp1_plus_exp2);
1384
- const VI exp2 = Sub(exp1_plus_exp2, exp1);
1385
- const VI exp3 = Sub(clamped_exp, exp1_plus_exp2);
1372
+ // If clamped_exp[i] < 0, ensure that 1 - kExpBias <= exp1[i] <= 0,
1373
+ // 1 - kExpBias <= exp2[i] <= 0, and 1 - kExpBias <= exp3[i] <= 0 are
1374
+ // true.
1386
1375
 
1387
- const VI exp_bias = Set(di, kExpBias);
1376
+ // In addition, if clamped_exp[i] < 1 - kExpBias, ensure that
1377
+ // exp3[i] == 1 - kExpBias to ensure results are correctly rounded if the
1378
+ // exact value of |x[i] * factor1[i] * factor2[i] * factor3[i]| is less than
1379
+ // the smallest positive normal value.
1380
+
1381
+ // Otherwise, if clamped_exp[i] >= 0, ensure that 0 <= exp1[i] <= kExpBias,
1382
+ // 0 <= exp2[i] <= kExpBias, and 0 <= exp3[i] <= kExpBias are all true.
1383
+
1384
+ const VI exp3 =
1385
+ BitCast(di, Clamp(BitCast(d_exp_min_max, clamped_exp),
1386
+ min_scale_factor_exp, max_scale_factor_exp));
1387
+
1388
+ const VI clamped_exp_minus_exp3 = Sub(clamped_exp, exp3);
1389
+ const VI exp2 =
1390
+ BitCast(di, Clamp(BitCast(d_exp_min_max, clamped_exp_minus_exp3),
1391
+ min_scale_factor_exp, max_scale_factor_exp));
1392
+ const VI exp1 = Sub(clamped_exp_minus_exp3, exp2);
1388
1393
 
1389
1394
  const VF factor1 =
1390
1395
  BitCast(df, ShiftLeft<kNumOfMantBits>(Add(exp1, exp_bias)));
@@ -1393,6 +1398,37 @@ HWY_API V MulByPow2(V v, VFromD<RebindToSigned<DFromV<V>>> exp) {
1393
1398
  const VF factor3 =
1394
1399
  BitCast(df, ShiftLeft<kNumOfMantBits>(Add(exp3, exp_bias)));
1395
1400
 
1401
+ // If exp2[i] < 0, then clamped_exp[i] < 1 - kExpBias and
1402
+ // exp3[i] == 1 - kExpBias will both be true. factor3[i] will be equal to the
1403
+ // smallest positive normal value if exp3[i] == 1 - kExpBias.
1404
+
1405
+ // If exp2[i] >= 0, then exp1[i] >= 0 and factor1[i] * factor2[i] >= 1.
1406
+
1407
+ // If exp2[i] < 0 and the exact value of |v[i] * factor1[i] * factor2[i]| is
1408
+ // less than the smallest positive normal value, then the exact value of
1409
+ // |v[i] * factor1[i] * factor2[i] * factor3[i]| will be much smaller than
1410
+ // half of the smallest positive denormal value (since factor3[i] will be
1411
+ // equal to the smallest positive normal value in this case), resulting in a
1412
+ // correctly rounded result in this case.
1413
+
1414
+ // If kExpBias >= kNumOfMantBits + 3 and exp3[i] == 1 - kExpBias are both
1415
+ // true, then factor3[i] will be small enough such that
1416
+ // v[i] * factor1[i] * factor2[i] * factor3[i] will be correctly rounded,
1417
+ // even if the exact value of |v[i] * factor1[i] * factor2[i]| is smaller than
1418
+ // the smallest positive normal value.
1419
+
1420
+ // kExpBias >= kNumOfMantBits + 3 is true for the F16, F32, and F64
1421
+ // floating-point types.
1422
+
1423
+ // Otherwise, either exp2[i] >= 0, the exact value of
1424
+ // |v[i] * factor1[i] * factor2[i]| is greater than or equal to the smallest
1425
+ // positive normal value, or v[i] is NaN. In these cases,
1426
+ // v[i] * factor1[i] * factor2[i] will either be exact or overflow to
1427
+ // infinity (if clamped_exp[i] > 0 and v[i] is a non-zero finite value),
1428
+ // resulting in a correctly rounded result if the exact value of
1429
+ // |v[i] * factor1[i] * factor2[i] * factor3[i]| is less than the smallest
1430
+ // positive normal value.
1431
+
1396
1432
  return Mul(Mul(Mul(v, factor1), factor2), factor3);
1397
1433
  }
1398
1434
 
@@ -3156,8 +3192,8 @@ HWY_API VFromD<D> GatherIndexN(D d, const T* HWY_RESTRICT base,
3156
3192
 
3157
3193
  template <class D, typename T = TFromD<D>>
3158
3194
  HWY_API VFromD<D> GatherIndexNOr(VFromD<D> no, D d, const T* HWY_RESTRICT base,
3159
- VFromD<RebindToSigned<D>> index,
3160
- const size_t max_lanes_to_load) {
3195
+ VFromD<RebindToSigned<D>> index,
3196
+ const size_t max_lanes_to_load) {
3161
3197
  const RebindToSigned<D> di;
3162
3198
  using TI = TFromD<decltype(di)>;
3163
3199
  static_assert(sizeof(T) == sizeof(TI), "Index/lane size must match");
@@ -3178,8 +3214,8 @@ HWY_API VFromD<D> GatherIndexN(D d, const T* HWY_RESTRICT base,
3178
3214
  }
3179
3215
  template <class D, typename T = TFromD<D>>
3180
3216
  HWY_API VFromD<D> GatherIndexNOr(VFromD<D> no, D d, const T* HWY_RESTRICT base,
3181
- VFromD<RebindToSigned<D>> index,
3182
- const size_t max_lanes_to_load) {
3217
+ VFromD<RebindToSigned<D>> index,
3218
+ const size_t max_lanes_to_load) {
3183
3219
  return MaskedGatherIndexOr(no, FirstN(d, max_lanes_to_load), d, base, index);
3184
3220
  }
3185
3221
  #endif // (defined(HWY_NATIVE_GATHER) == defined(HWY_TARGET_TOGGLE))
@@ -4525,43 +4561,46 @@ HWY_API V CLMulUpper(V a, V b) {
4525
4561
  #define HWY_NATIVE_POPCNT
4526
4562
  #endif
4527
4563
 
4528
- // This overload requires vectors to be at least 16 bytes, which is the case
4529
- // for LMUL >= 2.
4530
- #undef HWY_IF_POPCNT
4531
- #if HWY_TARGET == HWY_RVV
4532
- #define HWY_IF_POPCNT(D) \
4533
- hwy::EnableIf<D().Pow2() >= 1 && D().MaxLanes() >= 16>* = nullptr
4534
- #else
4535
- // Other targets only have these two overloads which are mutually exclusive, so
4536
- // no further conditions are required.
4537
- #define HWY_IF_POPCNT(D) void* = nullptr
4538
- #endif // HWY_TARGET == HWY_RVV
4539
-
4540
- template <class V, class D = DFromV<V>, HWY_IF_U8_D(D),
4541
- HWY_IF_V_SIZE_GT_D(D, 8), HWY_IF_POPCNT(D)>
4564
+ template <class V, class D = DFromV<V>, HWY_IF_U8_D(D)>
4542
4565
  HWY_API V PopulationCount(V v) {
4543
4566
  const D d;
4544
- const V lookup =
4545
- Dup128VecFromValues(d, 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4);
4546
- const auto lo = And(v, Set(d, uint8_t{0xF}));
4547
- const auto hi = ShiftRight<4>(v);
4548
- return Add(TableLookupBytes(lookup, hi), TableLookupBytes(lookup, lo));
4549
- }
4550
4567
 
4551
- // RVV has a specialization that avoids the Set().
4552
- #if HWY_TARGET != HWY_RVV
4553
- // Slower fallback for capped vectors.
4554
- template <class V, class D = DFromV<V>, HWY_IF_U8_D(D),
4555
- HWY_IF_V_SIZE_LE_D(D, 8)>
4556
- HWY_API V PopulationCount(V v) {
4557
- const D d;
4568
+ #if HWY_TARGET == HWY_SSE2
4569
+ // TableLookupBytes is slow on SSE2
4570
+
4558
4571
  // See https://arxiv.org/pdf/1611.07612.pdf, Figure 3
4559
4572
  const V k33 = Set(d, uint8_t{0x33});
4560
4573
  v = Sub(v, And(ShiftRight<1>(v), Set(d, uint8_t{0x55})));
4561
4574
  v = Add(And(ShiftRight<2>(v), k33), And(v, k33));
4562
4575
  return And(Add(v, ShiftRight<4>(v)), Set(d, uint8_t{0x0F}));
4576
+ #else // HWY_TARGET != HWY_SSE2
4577
+
4578
+ #if HWY_TARGET == HWY_RVV
4579
+ // Need at least LMUL=1 on RVV to ensure that Lanes(d_tbl) is at least 16
4580
+ const ScalableTag<uint8_t, HWY_MAX(HWY_POW2_D(D), 0)> d_tbl;
4581
+ #else
4582
+ const FixedTag<uint8_t, HWY_MAX(HWY_MAX_LANES_D(D), 16)> d_tbl;
4583
+ #endif
4584
+
4585
+ const auto lookup = Dup128VecFromValues(d_tbl, 0, 1, 1, 2, 1, 2, 2, 3, 1, 2,
4586
+ 2, 3, 2, 3, 3, 4);
4587
+ const auto lo = And(v, Set(d, uint8_t{0xF}));
4588
+ const auto hi = ShiftRight<4>(v);
4589
+
4590
+ #if HWY_TARGET == HWY_RVV
4591
+ // On RVV, use TableLookupLanes to avoid unnecessary overhead
4592
+ const auto hi_popcnt =
4593
+ ResizeBitCast(d, TableLookupLanes(lookup, ResizeBitCast(d_tbl, hi)));
4594
+ const auto lo_popcnt =
4595
+ ResizeBitCast(d, TableLookupLanes(lookup, ResizeBitCast(d_tbl, lo)));
4596
+ #else // HWY_TARGET != HWY_RVV
4597
+ const auto hi_popcnt = TableLookupBytes(lookup, hi);
4598
+ const auto lo_popcnt = TableLookupBytes(lookup, lo);
4599
+ #endif // HWY_TARGET == HWY_RVV
4600
+
4601
+ return Add(hi_popcnt, lo_popcnt);
4602
+ #endif // HWY_TARGET == HWY_SSE2
4563
4603
  }
4564
- #endif // HWY_TARGET != HWY_RVV
4565
4604
 
4566
4605
  template <class V, class D = DFromV<V>, HWY_IF_U16_D(D)>
4567
4606
  HWY_API V PopulationCount(V v) {
@@ -5323,14 +5362,13 @@ HWY_INLINE V IntDiv(V a, V b) {
5323
5362
  #endif // HWY_HAVE_FLOAT64
5324
5363
 
5325
5364
  template <size_t kOrigLaneSize, class V, HWY_IF_NOT_FLOAT_NOR_SPECIAL_V(V),
5326
- HWY_IF_T_SIZE_ONE_OF_V(V, ((HWY_TARGET <= HWY_SSE2 ||
5327
- HWY_TARGET == HWY_WASM ||
5328
- HWY_TARGET == HWY_WASM_EMU256 ||
5329
- HWY_TARGET == HWY_LSX ||
5330
- HWY_TARGET == HWY_LASX)
5331
- ? 0
5332
- : (1 << 1)) |
5333
- (1 << 2) | (1 << 4) | (1 << 8))>
5365
+ HWY_IF_T_SIZE_ONE_OF_V(
5366
+ V, ((HWY_TARGET <= HWY_SSE2 || HWY_TARGET == HWY_WASM ||
5367
+ HWY_TARGET == HWY_WASM_EMU256 || HWY_TARGET == HWY_LSX ||
5368
+ HWY_TARGET == HWY_LASX)
5369
+ ? 0
5370
+ : (1 << 1)) |
5371
+ (1 << 2) | (1 << 4) | (1 << 8))>
5334
5372
  HWY_INLINE V IntMod(V a, V b) {
5335
5373
  return hwy::HWY_NAMESPACE::NegMulAdd(IntDiv<kOrigLaneSize>(a, b), b, a);
5336
5374
  }
@@ -5474,17 +5512,15 @@ HWY_API V RoundingShiftRight(V v) {
5474
5512
  template <class V, HWY_IF_NOT_FLOAT_NOR_SPECIAL_V(V)>
5475
5513
  HWY_API V RoundingShiftRightSame(V v, int shift_amt) {
5476
5514
  const DFromV<V> d;
5477
- using T = TFromD<decltype(d)>;
5478
-
5479
- const int shift_amt_is_zero_mask = -static_cast<int>(shift_amt == 0);
5480
5515
 
5516
+ const bool shift_amt_is_zero = (shift_amt == 0);
5481
5517
  const auto scaled_down_v = ShiftRightSame(
5482
5518
  v, static_cast<int>(static_cast<unsigned>(shift_amt) +
5483
- static_cast<unsigned>(~shift_amt_is_zero_mask)));
5519
+ static_cast<unsigned>(shift_amt_is_zero) - 1u));
5484
5520
 
5485
5521
  return AverageRound(
5486
5522
  scaled_down_v,
5487
- And(scaled_down_v, Set(d, static_cast<T>(shift_amt_is_zero_mask))));
5523
+ IfThenElseZero(SetMask(d, shift_amt_is_zero), scaled_down_v));
5488
5524
  }
5489
5525
 
5490
5526
  template <class V, HWY_IF_NOT_FLOAT_NOR_SPECIAL_V(V)>
@@ -5531,7 +5567,7 @@ HWY_API VFromD<DF> MulOddAdd(DF df, VBF a, VBF b, VFromD<DF> c) {
5531
5567
 
5532
5568
  // ------------------------------ ReorderWidenMulAccumulate (MulEvenAdd)
5533
5569
 
5534
- // AVX3_SPR/ZEN4, and NEON with bf16 but not(!) SVE override this.
5570
+ // AVX3_SPR/ZEN4, NEON with bf16 and SVE override this.
5535
5571
  #if (defined(HWY_NATIVE_REORDER_WIDEN_MUL_ACC_BF16) == \
5536
5572
  defined(HWY_TARGET_TOGGLE))
5537
5573
  #ifdef HWY_NATIVE_REORDER_WIDEN_MUL_ACC_BF16
@@ -5551,6 +5587,13 @@ HWY_API VFromD<DF> ReorderWidenMulAccumulate(DF df, VBF a, VBF b,
5551
5587
  return MulEvenAdd(df, a, b, sum0);
5552
5588
  }
5553
5589
 
5590
+ template <class VW, HWY_IF_FLOAT_V(VW)>
5591
+ HWY_API VW RearrangeToOddPlusEven(const VW sum0, const VW sum1) {
5592
+ // sum1 contains the odd lanes and sum0 the even, hence their sum is the
5593
+ // desired pairwise sum.
5594
+ return Add(sum0, sum1);
5595
+ }
5596
+
5554
5597
  #endif // HWY_NATIVE_REORDER_WIDEN_MUL_ACC_BF16
5555
5598
 
5556
5599
  // ------------------------------ WidenMulAccumulate
@@ -5562,8 +5605,7 @@ HWY_API VFromD<DF> ReorderWidenMulAccumulate(DF df, VBF a, VBF b,
5562
5605
  #define HWY_NATIVE_WIDEN_MUL_ACCUMULATE
5563
5606
  #endif
5564
5607
 
5565
- template<class D, HWY_IF_INTEGER(TFromD<D>),
5566
- class DN = RepartitionToNarrow<D>>
5608
+ template <class D, HWY_IF_INTEGER(TFromD<D>), class DN = RepartitionToNarrow<D>>
5567
5609
  HWY_API VFromD<D> WidenMulAccumulate(D d, VFromD<DN> mul, VFromD<DN> x,
5568
5610
  VFromD<D> low, VFromD<D>& high) {
5569
5611
  high = MulAdd(PromoteUpperTo(d, mul), PromoteUpperTo(d, x), high);
@@ -5942,7 +5984,7 @@ HWY_API size_t CompressBitsStore(V v, const uint8_t* HWY_RESTRICT bits, D d,
5942
5984
  Store(v, d, lanes);
5943
5985
 
5944
5986
  const Simd<T, HWY_MIN(MaxLanes(d), 8), 0> d8;
5945
- T* HWY_RESTRICT pos = unaligned;
5987
+ T* pos = unaligned;
5946
5988
 
5947
5989
  HWY_ALIGN constexpr T table[2048] = {
5948
5990
  0, 1, 2, 3, 4, 5, 6, 7, /**/ 0, 1, 2, 3, 4, 5, 6, 7, //
@@ -6074,15 +6116,40 @@ HWY_API size_t CompressBitsStore(V v, const uint8_t* HWY_RESTRICT bits, D d,
6074
6116
  2, 3, 4, 5, 6, 7, 0, 1, /**/ 0, 2, 3, 4, 5, 6, 7, 1, //
6075
6117
  1, 2, 3, 4, 5, 6, 7, 0, /**/ 0, 1, 2, 3, 4, 5, 6, 7};
6076
6118
 
6077
- for (size_t i = 0; i < Lanes(d); i += 8) {
6078
- // Each byte worth of bits is the index of one of 256 8-byte ranges, and its
6079
- // population count determines how far to advance the write position.
6080
- const size_t bits8 = bits[i / 8];
6081
- const auto indices = Load(d8, table + bits8 * 8);
6082
- const auto compressed = TableLookupBytes(LoadU(d8, lanes + i), indices);
6083
- StoreU(compressed, d8, pos);
6084
- pos += PopCount(bits8);
6119
+ size_t i = 0;
6120
+ HWY_LANES_CONSTEXPR size_t N = Lanes(d);
6121
+ constexpr bool kMaybeLt128 =
6122
+ (HWY_TARGET == HWY_SCALAR) || !detail::IsFull(D());
6123
+ // If less than 128 bit, we may not enter the main loop below, and even
6124
+ // the remainder loop might not write anything if bits are not set.
6125
+ // Ensure the output is initialized. GCC seems not to understand this is only
6126
+ // necessary if kMaybeLt128.
6127
+ HWY_IF_CONSTEXPR(kMaybeLt128 || HWY_COMPILER_GCC_ACTUAL) {
6128
+ StoreU(v, d, unaligned);
6129
+ }
6130
+ HWY_ASSUME(N >= 8 || kMaybeLt128);
6131
+ if (N >= 8) {
6132
+ for (; i <= N - 8; i += 8) {
6133
+ // Each byte worth of bits is the index of one of 256 8-byte ranges, and
6134
+ // its population count determines how far to advance the write position.
6135
+ const size_t bits8 = bits[i / 8];
6136
+ const auto indices = Load(d8, table + bits8 * 8);
6137
+ const auto compressed = TableLookupBytes(LoadU(d8, lanes + i), indices);
6138
+ StoreU(compressed, d8, pos);
6139
+ pos += PopCount(bits8);
6140
+ }
6085
6141
  }
6142
+ // Not required if we have full vectors of >= 128 bits, because they are
6143
+ // multiples of 8 bytes. Inefficient loop is mainly required for safely
6144
+ // handling compress_test).
6145
+ HWY_IF_CONSTEXPR(kMaybeLt128) {
6146
+ for (; i < N; ++i) {
6147
+ if (bits[i / 8] & (1u << (i % 8))) {
6148
+ *pos++ = lanes[i];
6149
+ }
6150
+ }
6151
+ }
6152
+
6086
6153
  return static_cast<size_t>(pos - unaligned);
6087
6154
  }
6088
6155
 
@@ -6775,12 +6842,19 @@ HWY_API Vec128<T, 1> Expand(Vec128<T, 1> v, Mask128<T, 1> mask) {
6775
6842
  }
6776
6843
 
6777
6844
  // ------------------------------ LoadExpand
6845
+
6846
+ // #2957: clangd warning because x86_128-inl.h defines an overload with this
6847
+ // condition, so negate it here.
6848
+ #if !(HWY_TARGET <= HWY_AVX3 || HWY_IDE)
6849
+
6778
6850
  template <class D, HWY_IF_V_SIZE_LE_D(D, 16)>
6779
6851
  HWY_API VFromD<D> LoadExpand(MFromD<D> mask, D d,
6780
6852
  const TFromD<D>* HWY_RESTRICT unaligned) {
6781
6853
  return Expand(LoadU(d, unaligned), mask);
6782
6854
  }
6783
6855
 
6856
+ #endif // !(HWY_TARGET <= HWY_AVX3 || HWY_IDE)
6857
+
6784
6858
  #endif // HWY_NATIVE_EXPAND
6785
6859
 
6786
6860
  // ------------------------------ TwoTablesLookupLanes
@@ -6798,6 +6872,72 @@ HWY_API VFromD<D> TwoTablesLookupLanes(D /*d*/, VFromD<D> a, VFromD<D> b,
6798
6872
  }
6799
6873
  #endif
6800
6874
 
6875
+ // ------------------------------ Lookup8
6876
+
6877
+ template <class D, typename T = TFromD<D>, class VI>
6878
+ HWY_INLINE Vec<D> Lookup8(D d, const T* HWY_RESTRICT table, VI indices) {
6879
+ // `di` describes the indices given - same bits per lane, but `d` determines
6880
+ // the actual lane count of the result and also of the table vectors, which
6881
+ // is relevant for adjusting the index values, see below.
6882
+ DFromV<VI> di;
6883
+ static_assert(sizeof(T) == sizeof(TFromD<decltype(di)>),
6884
+ "Index/vector must have same lane size");
6885
+ HWY_IF_CONSTEXPR(HWY_IS_DEBUG_BUILD) {
6886
+ // Asserting Lanes(di) >= 4 not needed since both d and di have the same
6887
+ // number of Lanes()
6888
+ HWY_DASSERT(Lanes(d) >= 4);
6889
+ HWY_DASSERT(AllTrue(di, Lt(indices, Set(di, 8))));
6890
+ }
6891
+
6892
+ HWY_IF_CONSTEXPR(!HWY_HAVE_SCALABLE) {
6893
+ // Fixed-size vectors: we know they are >= 128 bit, so either one or two
6894
+ // tables are sufficient.
6895
+ HWY_IF_CONSTEXPR(MaxLanes(d) >= 8) {
6896
+ const CappedTag<T, 8> d8;
6897
+ // We want to perform one lookup per index, hence cast. This has no
6898
+ // runtime cost; the upper lanes are unused.
6899
+ const Vec<D> t0 = ResizeBitCast(d, Load(d8, table));
6900
+ return TableLookupLanes(t0, IndicesFromVec(d, indices));
6901
+ }
6902
+ HWY_IF_CONSTEXPR(MaxLanes(d) < 8) {
6903
+ // Exactly 4 lanes, because we ensured >= 4 above.
6904
+ const Vec<D> t0 = Load(d, table);
6905
+ const Vec<D> t1 = Load(d, table + 4);
6906
+ return TwoTablesLookupLanes(d, t0, t1, IndicesFromVec(d, indices));
6907
+ }
6908
+ }
6909
+
6910
+ HWY_IF_CONSTEXPR(HWY_HAVE_SCALABLE) {
6911
+ // Scalable: first we must load two halves of the table into two vectors,
6912
+ // regardless of vector size. We always use two-vector lookups to avoid
6913
+ // runtime branching. Note that RVV can have U64x8 even with 128-bit
6914
+ // vectors (LMUL=4), hence we must use the given LMUL, not FixedTag, but we
6915
+ // still want to cap at 4 lanes to avoid overrunning the table.
6916
+ const CappedTag<T, 4, d.Pow2()> d4;
6917
+
6918
+ // We want to use native lookup instructions (more efficient on SVE than two
6919
+ // lookups plus a blend), hence cast. This has no runtime cost. No LoadU
6920
+ // required because + 4 is still aligned relative to `d4`.
6921
+ const Vec<D> t0 = ResizeBitCast(d, Load(d4, table));
6922
+ const Vec<D> t1 = ResizeBitCast(d, Load(d4, table + 4));
6923
+
6924
+ // Now ensure indices for the second half of the table point to the second
6925
+ // vector. Note that SVE2_128 and SVE_256 are handled by the fixed-size case
6926
+ // above. The adjustment factor is 0 for 128-bit SIMD, which can happen with
6927
+ // 128-bit SVE1 hardware, but we do not know that at compile time.
6928
+ using TI = TFromD<decltype(di)>;
6929
+ const VI adjust = Set(di, static_cast<TI>(Lanes(d) - 4));
6930
+ #if HWY_TARGET_IS_SVE
6931
+ const Mask<decltype(di)> ge_4 = detail::GeN(indices, 4);
6932
+ #else
6933
+ const Mask<decltype(di)> ge_4 = Ge(indices, Set(di, 4));
6934
+ #endif
6935
+ indices = MaskedAddOr(indices, ge_4, indices, adjust);
6936
+
6937
+ return TwoTablesLookupLanes(d, t0, t1, IndicesFromVec(d, indices));
6938
+ }
6939
+ }
6940
+
6801
6941
  // ------------------------------ Reverse2, Reverse4, Reverse8 (8-bit)
6802
6942
 
6803
6943
  #if (defined(HWY_NATIVE_REVERSE2_8) == defined(HWY_TARGET_TOGGLE)) || HWY_IDE
@@ -15,11 +15,28 @@
15
15
  // 256-bit LASX vectors and operations.
16
16
  // External include guard in highway.h - see comment there.
17
17
 
18
- #include <lasxintrin.h>
19
-
20
18
  #include "hwy/ops/loongarch_lsx-inl.h"
21
19
  #include "hwy/ops/shared-inl.h"
22
20
 
21
+ #ifndef __loongarch_asx
22
+ // If LASX is to be runtime dispatched (instead of in baseline), we need
23
+ // to enable it *and* define __loongarch_asx or the intrinsic header will
24
+ // fail to compile.
25
+ //
26
+ // For consistency, the same pattern as the lsxintrin.h handling in
27
+ // loongarch_lsx-inl.h is used (instead of moving lasxintrin.h after
28
+ // HWY_BEFORE_NAMESPACE).
29
+ HWY_PUSH_ATTRIBUTES("lsx,lasx")
30
+ #define __loongarch_asx
31
+ #include <lasxintrin.h>
32
+ #undef __loongarch_asx
33
+ // Prevent "unused push_attribute" warning from Clang.
34
+ HWY_MAYBE_UNUSED static void HWY_CONCAT(hwy_lasx_dummy, __COUNTER__) () {}
35
+ HWY_POP_ATTRIBUTES
36
+ #else
37
+ #include <lasxintrin.h>
38
+ #endif
39
+
23
40
  HWY_BEFORE_NAMESPACE();
24
41
  namespace hwy {
25
42
  namespace HWY_NAMESPACE {
@@ -372,12 +389,6 @@ HWY_API Vec256<T> Not(const Vec256<T> v) {
372
389
  BitCast(du, v).raw)});
373
390
  }
374
391
 
375
- // ------------------------------ Xor3
376
- template <typename T>
377
- HWY_API Vec256<T> Xor3(Vec256<T> x1, Vec256<T> x2, Vec256<T> x3) {
378
- return Xor(x1, Xor(x2, x3));
379
- }
380
-
381
392
  // ------------------------------ Or3
382
393
  template <typename T>
383
394
  HWY_API Vec256<T> Or3(Vec256<T> o1, Vec256<T> o2, Vec256<T> o3) {
@@ -2462,7 +2473,7 @@ HWY_API Vec256<T> TableLookupLanes(Vec256<T> v, Indices256<T> idx) {
2462
2473
  // Replicate 64-bit index into upper 32 bits
2463
2474
  const Vec256<TI> dup{__lasx_xvpackev_w(idx.raw, idx.raw)};
2464
2475
  // For each idx64 i, idx32 are 2*i and 2*i+1.
2465
- const Vec256<TI> idx32 = dup + dup + Set(di64, int64_t(1) << 32);
2476
+ const Vec256<TI> idx32 = dup + dup + Set(di64, int64_t{1} << 32);
2466
2477
  return BitCast(
2467
2478
  d, TableLookupLanes(BitCast(di32, v), Indices256<int32_t>{idx32.raw}));
2468
2479
  }
@@ -2515,6 +2526,17 @@ HWY_API V InterleaveOddBlocks(D d, V a, V b) {
2515
2526
  return ConcatUpperUpper(d, b, a);
2516
2527
  }
2517
2528
 
2529
+ // ------------------------------ InterleaveLowerBlocks
2530
+ template <class D, class V = VFromD<D>, HWY_IF_V_SIZE_D(D, 32)>
2531
+ HWY_API V InterleaveLowerBlocks(D d, V a, V b) {
2532
+ return InterleaveEvenBlocks(d, a, b);
2533
+ }
2534
+ // ------------------------------ InterleaveUpperBlocks
2535
+ template <class D, class V = VFromD<D>, HWY_IF_V_SIZE_D(D, 32)>
2536
+ HWY_API V InterleaveUpperBlocks(D d, V a, V b) {
2537
+ return InterleaveOddBlocks(d, a, b);
2538
+ }
2539
+
2518
2540
  // ------------------------------ Reverse (RotateRight)
2519
2541
 
2520
2542
  template <class D, HWY_IF_V_SIZE_D(D, 32), HWY_IF_T_SIZE_D(D, 4)>