react-native-executorch 0.10.5 → 0.10.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 (251) hide show
  1. package/README.md +10 -1
  2. package/android/build.gradle.kts +4 -3
  3. package/ios/RnExecutorch.mm +15 -17
  4. package/lib/module/fetcher/fetcher.js +35 -122
  5. package/lib/module/fetcher/fetcher.js.map +1 -1
  6. package/lib/module/fetcher/telemetry.js +1 -1
  7. package/lib/module/index.js +12 -13
  8. package/lib/module/index.js.map +1 -1
  9. package/lib/module/models.js +4 -2
  10. package/lib/module/models.js.map +1 -1
  11. package/lib/typescript/src/fetcher/fetcher.d.ts +3 -7
  12. package/lib/typescript/src/fetcher/fetcher.d.ts.map +1 -1
  13. package/lib/typescript/src/models.d.ts.map +1 -1
  14. package/package.json +9 -7
  15. package/react-native-executorch.podspec +6 -2
  16. package/src/fetcher/fetcher.ts +38 -131
  17. package/src/fetcher/telemetry.ts +1 -1
  18. package/src/models.ts +6 -1
  19. package/third-party/common/phonemis/CMakeLists.txt +70 -14
  20. package/third-party/common/phonemis/README.md +183 -33
  21. package/third-party/common/phonemis/THIRD_PARTY_NOTICES.md +57 -0
  22. package/third-party/common/phonemis/knowledge/code_style.md +642 -0
  23. package/third-party/common/phonemis/licenses/Unicode-3.0.txt +39 -0
  24. package/third-party/common/phonemis/licenses/misaki-Apache-2.0.txt +201 -0
  25. package/third-party/common/phonemis/licenses/nlohmann-json-MIT.txt +21 -0
  26. package/third-party/common/phonemis/licenses/xsimd-BSD-3-Clause.txt +29 -0
  27. package/third-party/common/phonemis/src/phonemis/base/config.h +6 -0
  28. package/third-party/common/phonemis/src/phonemis/base/ipipeline.cpp +75 -0
  29. package/third-party/common/phonemis/src/phonemis/base/ipipeline.h +21 -0
  30. package/third-party/common/phonemis/src/phonemis/base/phonemizer/constants.h +2 -5
  31. package/third-party/common/phonemis/src/phonemis/base/phonemizer/lexicon_phonemizer.cpp +3 -4
  32. package/third-party/common/phonemis/src/phonemis/base/phonemizer/nn/neural_phonemizer.cpp +17 -8
  33. package/third-party/common/phonemis/src/phonemis/base/phonemizer/nn/neural_phonemizer.h +4 -0
  34. package/third-party/common/phonemis/src/phonemis/base/phonemizer/nn/tokenizer.cpp +21 -6
  35. package/third-party/common/phonemis/src/phonemis/base/phonemizer/nn/tokenizer.h +13 -4
  36. package/third-party/common/phonemis/src/phonemis/base/pipeline.cpp +8 -0
  37. package/third-party/common/phonemis/src/phonemis/base/pipeline.h +19 -0
  38. package/third-party/common/phonemis/src/phonemis/base/processor/common/conditions.cpp +37 -0
  39. package/third-party/common/phonemis/src/phonemis/base/processor/common/conditions.h +45 -0
  40. package/third-party/common/phonemis/src/phonemis/base/processor/common/constants.h +10 -0
  41. package/third-party/common/phonemis/src/phonemis/base/processor/common/context.cpp +105 -0
  42. package/third-party/common/phonemis/src/phonemis/base/processor/common/context.h +49 -0
  43. package/third-party/common/phonemis/src/phonemis/base/processor/common/document.cpp +173 -0
  44. package/third-party/common/phonemis/src/phonemis/base/processor/common/document.h +67 -0
  45. package/third-party/common/phonemis/src/phonemis/base/processor/common/text.cpp +75 -0
  46. package/third-party/common/phonemis/src/phonemis/base/processor/common/text.h +60 -0
  47. package/third-party/common/phonemis/src/phonemis/base/processor/common/types.h +18 -0
  48. package/third-party/common/phonemis/src/phonemis/base/processor/config.h +53 -0
  49. package/third-party/common/phonemis/src/phonemis/base/processor/layer.h +9 -7
  50. package/third-party/common/phonemis/src/phonemis/base/processor/layers/normalize/constants.h +20 -0
  51. package/third-party/common/phonemis/src/phonemis/base/processor/layers/normalize/layer.cpp +89 -0
  52. package/third-party/common/phonemis/src/phonemis/base/processor/layers/normalize/layer.h +35 -0
  53. package/third-party/common/phonemis/src/phonemis/base/processor/layers/normalize/types.h +16 -0
  54. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/kind.h +40 -0
  55. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/layer.h +382 -0
  56. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/notation.h +30 -0
  57. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/numerals.cpp +51 -0
  58. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/numerals.h +31 -0
  59. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/pattern.h +30 -0
  60. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/pattern_set.cpp +17 -0
  61. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/pattern_set.h +31 -0
  62. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/patterns.cpp +811 -0
  63. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/patterns.h +285 -0
  64. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/primitives.cpp +64 -0
  65. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/primitives.h +23 -0
  66. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/types.h +94 -0
  67. package/third-party/common/phonemis/src/phonemis/base/processor/layers/sanitizer/layer.cpp +19 -0
  68. package/third-party/common/phonemis/src/phonemis/base/processor/{sanitizer_layer.h → layers/sanitizer/layer.h} +8 -8
  69. package/third-party/common/phonemis/src/phonemis/base/processor/layers/sym2word/layer.cpp +65 -0
  70. package/third-party/common/phonemis/src/phonemis/base/processor/layers/sym2word/layer.h +29 -0
  71. package/third-party/common/phonemis/src/phonemis/base/processor/layers/term2word/layer.cpp +170 -0
  72. package/third-party/common/phonemis/src/phonemis/base/processor/layers/term2word/layer.h +40 -0
  73. package/third-party/common/phonemis/src/phonemis/base/processor/layers/term2word/types.h +25 -0
  74. package/third-party/common/phonemis/src/phonemis/base/processor/layers/trim/layer.cpp +47 -0
  75. package/third-party/common/phonemis/src/phonemis/base/processor/layers/trim/layer.h +19 -0
  76. package/third-party/common/phonemis/src/phonemis/base/processor/preprocessor.cpp +60 -0
  77. package/third-party/common/phonemis/src/phonemis/base/processor/preprocessor.h +45 -0
  78. package/third-party/common/phonemis/src/phonemis/base/processor/processor.cpp +6 -7
  79. package/third-party/common/phonemis/src/phonemis/base/processor/processor.h +14 -10
  80. package/third-party/common/phonemis/src/phonemis/base/tagger/hmm_tagger.cpp +89 -52
  81. package/third-party/common/phonemis/src/phonemis/base/tagger/hmm_tagger.h +16 -9
  82. package/third-party/common/phonemis/src/phonemis/base/tokenizer/tokenizer.cpp +13 -12
  83. package/third-party/common/phonemis/src/phonemis/lang/de/constants.h +183 -19
  84. package/third-party/common/phonemis/src/phonemis/lang/de/num2word.cpp +355 -309
  85. package/third-party/common/phonemis/src/phonemis/lang/de/num2word.h +42 -17
  86. package/third-party/common/phonemis/src/phonemis/lang/de/patterns.cpp +56 -0
  87. package/third-party/common/phonemis/src/phonemis/lang/de/patterns.h +15 -0
  88. package/third-party/common/phonemis/src/phonemis/lang/de/pipeline.h +3 -3
  89. package/third-party/common/phonemis/src/phonemis/lang/en/constants.h +181 -30
  90. package/third-party/common/phonemis/src/phonemis/lang/en/hmm_tagger.cpp +5 -7
  91. package/third-party/common/phonemis/src/phonemis/lang/en/num2word.cpp +232 -135
  92. package/third-party/common/phonemis/src/phonemis/lang/en/num2word.h +41 -16
  93. package/third-party/common/phonemis/src/phonemis/lang/en/pipeline.h +3 -10
  94. package/third-party/common/phonemis/src/phonemis/lang/es/constants.h +182 -60
  95. package/third-party/common/phonemis/src/phonemis/lang/es/num2word.cpp +247 -212
  96. package/third-party/common/phonemis/src/phonemis/lang/es/num2word.h +38 -18
  97. package/third-party/common/phonemis/src/phonemis/lang/es/patterns.cpp +50 -0
  98. package/third-party/common/phonemis/src/phonemis/lang/es/patterns.h +15 -0
  99. package/third-party/common/phonemis/src/phonemis/lang/es/pipeline.h +3 -3
  100. package/third-party/common/phonemis/src/phonemis/lang/fr/constants.h +152 -26
  101. package/third-party/common/phonemis/src/phonemis/lang/fr/num2word.cpp +252 -179
  102. package/third-party/common/phonemis/src/phonemis/lang/fr/num2word.h +38 -15
  103. package/third-party/common/phonemis/src/phonemis/lang/fr/patterns.cpp +83 -0
  104. package/third-party/common/phonemis/src/phonemis/lang/fr/patterns.h +15 -0
  105. package/third-party/common/phonemis/src/phonemis/lang/fr/pipeline.h +3 -3
  106. package/third-party/common/phonemis/src/phonemis/lang/hi/constants.h +62 -10
  107. package/third-party/common/phonemis/src/phonemis/lang/hi/num2word.cpp +74 -123
  108. package/third-party/common/phonemis/src/phonemis/lang/hi/num2word.h +27 -16
  109. package/third-party/common/phonemis/src/phonemis/lang/hi/pipeline.h +5 -3
  110. package/third-party/common/phonemis/src/phonemis/lang/it/constants.h +122 -42
  111. package/third-party/common/phonemis/src/phonemis/lang/it/num2word.cpp +200 -207
  112. package/third-party/common/phonemis/src/phonemis/lang/it/num2word.h +30 -18
  113. package/third-party/common/phonemis/src/phonemis/lang/it/patterns.cpp +25 -0
  114. package/third-party/common/phonemis/src/phonemis/lang/it/patterns.h +15 -0
  115. package/third-party/common/phonemis/src/phonemis/lang/it/pipeline.h +3 -3
  116. package/third-party/common/phonemis/src/phonemis/lang/pl/constants.h +346 -77
  117. package/third-party/common/phonemis/src/phonemis/lang/pl/num2word.cpp +631 -246
  118. package/third-party/common/phonemis/src/phonemis/lang/pl/num2word.h +47 -15
  119. package/third-party/common/phonemis/src/phonemis/lang/pl/pipeline.h +6 -6
  120. package/third-party/common/phonemis/src/phonemis/lang/pt/constants.h +201 -0
  121. package/third-party/common/phonemis/src/phonemis/lang/pt/num2word.cpp +365 -0
  122. package/third-party/common/phonemis/src/phonemis/lang/pt/num2word.h +53 -0
  123. package/third-party/common/phonemis/src/phonemis/lang/pt/pipeline.h +4 -2
  124. package/third-party/common/phonemis/src/phonemis/main.cpp +42 -11
  125. package/third-party/common/phonemis/src/phonemis/protophone/meta.h +24 -0
  126. package/third-party/common/phonemis/src/phonemis/protophone/numeric.h +26 -0
  127. package/third-party/common/phonemis/src/phonemis/protophone/protophone.cpp +525 -0
  128. package/third-party/common/phonemis/src/phonemis/protophone/protophone.h +80 -0
  129. package/third-party/common/phonemis/src/phonemis/protophone/tensor.h +76 -0
  130. package/third-party/common/phonemis/src/phonemis/protophone/tensor_utils.h +89 -0
  131. package/third-party/common/phonemis/src/phonemis/protophone/tensor_view.h +125 -0
  132. package/third-party/common/phonemis/src/phonemis/protophone/types.h +43 -0
  133. package/third-party/common/phonemis/src/phonemis/utils/strings.h +20 -14
  134. package/third-party/common/phonemis/src/phonemis/utils/unicode.h +15 -1
  135. package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_arithmetic.hpp +267 -0
  136. package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_bit.hpp +232 -0
  137. package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_cast.hpp +43 -0
  138. package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_complex.hpp +112 -0
  139. package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_details.hpp +386 -0
  140. package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_logical.hpp +240 -0
  141. package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_math.hpp +2601 -0
  142. package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_memory.hpp +1006 -0
  143. package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_rounding.hpp +72 -0
  144. package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_swizzle.hpp +260 -0
  145. package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_trigo.hpp +996 -0
  146. package/third-party/common/phonemis/src/third-party/xsimd/arch/utils/shifts.hpp +82 -0
  147. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx.hpp +2111 -0
  148. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx2.hpp +1591 -0
  149. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx2_128.hpp +170 -0
  150. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512bw.hpp +724 -0
  151. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512cd.hpp +28 -0
  152. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512dq.hpp +270 -0
  153. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512er.hpp +17 -0
  154. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512f.hpp +2919 -0
  155. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512ifma.hpp +17 -0
  156. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512pf.hpp +17 -0
  157. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512vbmi.hpp +76 -0
  158. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512vbmi2.hpp +130 -0
  159. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512vnni_avx512bw.hpp +17 -0
  160. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512vnni_avx512vbmi2.hpp +17 -0
  161. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx_128.hpp +164 -0
  162. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avxvnni.hpp +17 -0
  163. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_common.hpp +26 -0
  164. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_common_fwd.hpp +127 -0
  165. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_constants.hpp +393 -0
  166. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_emulated.hpp +787 -0
  167. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_fma3_avx.hpp +93 -0
  168. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_fma3_avx2.hpp +46 -0
  169. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_fma3_sse.hpp +97 -0
  170. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_fma4.hpp +92 -0
  171. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_i8mm_neon64.hpp +17 -0
  172. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_isa.hpp +148 -0
  173. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_neon.hpp +3580 -0
  174. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_neon64.hpp +1614 -0
  175. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_rvv.hpp +1515 -0
  176. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_scalar.hpp +1210 -0
  177. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_sse2.hpp +2333 -0
  178. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_sse3.hpp +66 -0
  179. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_sse4_1.hpp +510 -0
  180. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_sse4_2.hpp +44 -0
  181. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_ssse3.hpp +186 -0
  182. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_sve.hpp +1186 -0
  183. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_vsx.hpp +947 -0
  184. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_vxe.hpp +787 -0
  185. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_wasm.hpp +1819 -0
  186. package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_arch.hpp +242 -0
  187. package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_config.hpp +633 -0
  188. package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_cpu_features.hpp +50 -0
  189. package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_cpu_features_arm.hpp +132 -0
  190. package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_cpu_features_ppc.hpp +54 -0
  191. package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_cpu_features_riscv.hpp +95 -0
  192. package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_cpu_features_s390x.hpp +56 -0
  193. package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_cpu_features_x86.hpp +1121 -0
  194. package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_cpuid.hpp +144 -0
  195. package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_getauxval.hpp +159 -0
  196. package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_macros.hpp +78 -0
  197. package/third-party/common/phonemis/src/third-party/xsimd/math/xsimd_rem_pio2.hpp +707 -0
  198. package/third-party/common/phonemis/src/third-party/xsimd/memory/xsimd_aligned_allocator.hpp +349 -0
  199. package/third-party/common/phonemis/src/third-party/xsimd/memory/xsimd_alignment.hpp +102 -0
  200. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_all_registers.hpp +57 -0
  201. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_api.hpp +3106 -0
  202. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx2_register.hpp +57 -0
  203. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512bw_register.hpp +51 -0
  204. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512cd_register.hpp +51 -0
  205. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512dq_register.hpp +51 -0
  206. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512er_register.hpp +51 -0
  207. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512f_register.hpp +77 -0
  208. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512ifma_register.hpp +51 -0
  209. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512pf_register.hpp +51 -0
  210. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512vbmi2_register.hpp +51 -0
  211. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512vbmi_register.hpp +51 -0
  212. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512vnni_avx512bw_register.hpp +54 -0
  213. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512vnni_avx512vbmi2_register.hpp +53 -0
  214. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx_register.hpp +79 -0
  215. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avxvnni_register.hpp +44 -0
  216. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_batch.hpp +1666 -0
  217. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_batch_constant.hpp +572 -0
  218. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_batch_fwd.hpp +41 -0
  219. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_common_arch.hpp +49 -0
  220. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_emulated_register.hpp +80 -0
  221. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_fma3_avx2_register.hpp +50 -0
  222. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_fma3_avx_register.hpp +50 -0
  223. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_fma3_sse_register.hpp +50 -0
  224. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_fma4_register.hpp +50 -0
  225. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_i8mm_neon64_register.hpp +55 -0
  226. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_neon64_register.hpp +55 -0
  227. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_neon_register.hpp +130 -0
  228. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_register.hpp +96 -0
  229. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_rvv_register.hpp +491 -0
  230. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_sse2_register.hpp +59 -0
  231. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_sse3_register.hpp +49 -0
  232. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_sse4_1_register.hpp +48 -0
  233. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_sse4_2_register.hpp +48 -0
  234. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_ssse3_register.hpp +48 -0
  235. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_sve_register.hpp +216 -0
  236. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_traits.hpp +409 -0
  237. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_utils.hpp +462 -0
  238. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_vsx_register.hpp +84 -0
  239. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_vxe_register.hpp +86 -0
  240. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_wasm_register.hpp +59 -0
  241. package/third-party/common/phonemis/src/third-party/xsimd/utils/bits.hpp +122 -0
  242. package/third-party/common/phonemis/src/third-party/xsimd/utils/xsimd_type_traits.hpp +145 -0
  243. package/third-party/common/phonemis/src/third-party/xsimd/xsimd.hpp +43 -0
  244. package/third-party/common/phonemis/src/phonemis/base/processor/constants.h +0 -11
  245. package/third-party/common/phonemis/src/phonemis/base/processor/num2word/config.h +0 -16
  246. package/third-party/common/phonemis/src/phonemis/base/processor/num2word/layer.cpp +0 -271
  247. package/third-party/common/phonemis/src/phonemis/base/processor/num2word/layer.h +0 -45
  248. package/third-party/common/phonemis/src/phonemis/base/processor/num2word/types.h +0 -29
  249. package/third-party/common/phonemis/src/phonemis/base/processor/sanitizer_layer.cpp +0 -22
  250. package/third-party/common/phonemis/src/phonemis/base/processor/trim_layer.cpp +0 -40
  251. package/third-party/common/phonemis/src/phonemis/base/processor/trim_layer.h +0 -22
@@ -0,0 +1,2919 @@
1
+ /***************************************************************************
2
+ * Copyright (c) Johan Mabille, Sylvain Corlay, Wolf Vollprecht and *
3
+ * Martin Renou *
4
+ * Copyright (c) QuantStack *
5
+ * Copyright (c) Serge Guelton *
6
+ * *
7
+ * Distributed under the terms of the BSD 3-Clause License. *
8
+ * *
9
+ * The full license is in the file LICENSE, distributed with this software. *
10
+ ****************************************************************************/
11
+
12
+ #ifndef XSIMD_AVX512F_HPP
13
+ #define XSIMD_AVX512F_HPP
14
+
15
+ #include <complex>
16
+ #include <limits>
17
+ #include <type_traits>
18
+
19
+ #include "../types/xsimd_avx512f_register.hpp"
20
+ #include "../types/xsimd_batch_constant.hpp"
21
+
22
+ namespace xsimd
23
+ {
24
+
25
+ namespace kernel
26
+ {
27
+ using namespace types;
28
+
29
+ // fwd
30
+ template <class A, class T, class Mask>
31
+ XSIMD_INLINE batch<T, A> decr_if(batch<T, A> const& self, Mask const& mask, requires_arch<common>) noexcept;
32
+ template <class A, class T, class Mask>
33
+ XSIMD_INLINE batch<T, A> incr_if(batch<T, A> const& self, Mask const& mask, requires_arch<common>) noexcept;
34
+ template <class A, class T, size_t I>
35
+ XSIMD_INLINE batch<T, A> insert(batch<T, A> const& self, T val, index<I>, requires_arch<common>) noexcept;
36
+ template <class A, class T, class ITy, ITy... Is>
37
+ XSIMD_INLINE batch<T, A> swizzle(batch<T, A> const& self, batch_constant<ITy, A, Is...>, requires_arch<common>) noexcept;
38
+ template <class A>
39
+ XSIMD_INLINE void transpose(batch<uint16_t, A>* matrix_begin, batch<uint16_t, A>* matrix_end, requires_arch<common>) noexcept;
40
+ template <class A>
41
+ XSIMD_INLINE void transpose(batch<uint8_t, A>* matrix_begin, batch<uint8_t, A>* matrix_end, requires_arch<common>) noexcept;
42
+
43
+ namespace detail
44
+ {
45
+ XSIMD_INLINE __m256 lower_half(__m512 self) noexcept
46
+ {
47
+ return _mm512_castps512_ps256(self);
48
+ }
49
+ XSIMD_INLINE __m256d lower_half(__m512d self) noexcept
50
+ {
51
+ return _mm512_castpd512_pd256(self);
52
+ }
53
+ XSIMD_INLINE __m256i lower_half(__m512i self) noexcept
54
+ {
55
+ return _mm512_castsi512_si256(self);
56
+ }
57
+ XSIMD_INLINE __m256 upper_half(__m512 self) noexcept
58
+ {
59
+ return _mm256_castsi256_ps(_mm512_extracti64x4_epi64(_mm512_castps_si512(self), 1));
60
+ }
61
+ XSIMD_INLINE __m256d upper_half(__m512d self) noexcept
62
+ {
63
+ return _mm512_extractf64x4_pd(self, 1);
64
+ }
65
+ XSIMD_INLINE __m256i upper_half(__m512i self) noexcept
66
+ {
67
+ return _mm512_extracti64x4_epi64(self, 1);
68
+ }
69
+ XSIMD_INLINE __m512i merge_avx(__m256i low, __m256i high) noexcept
70
+ {
71
+ return _mm512_inserti64x4(_mm512_castsi256_si512(low), high, 1);
72
+ }
73
+ XSIMD_INLINE __m512 merge_avx(__m256 low, __m256 high) noexcept
74
+ {
75
+ return _mm512_castpd_ps(_mm512_insertf64x4(_mm512_castpd256_pd512(_mm256_castps_pd(low)), _mm256_castps_pd(high), 1));
76
+ }
77
+ XSIMD_INLINE __m512d merge_avx(__m256d low, __m256d high) noexcept
78
+ {
79
+ return _mm512_insertf64x4(_mm512_castpd256_pd512(low), high, 1);
80
+ }
81
+
82
+ template <class F>
83
+ __m512i fwd_to_avx(F f, __m512i self)
84
+ {
85
+ __m256i self_low = lower_half(self), self_high = upper_half(self);
86
+ __m256i res_low = f(self_low);
87
+ __m256i res_high = f(self_high);
88
+ return merge_avx(res_low, res_high);
89
+ }
90
+ template <class F>
91
+ __m512i fwd_to_avx(F f, __m512i self, __m512i other)
92
+ {
93
+ __m256i self_low = lower_half(self), self_high = upper_half(self),
94
+ other_low = lower_half(other), other_high = upper_half(other);
95
+ __m256i res_low = f(self_low, other_low);
96
+ __m256i res_high = f(self_high, other_high);
97
+ return merge_avx(res_low, res_high);
98
+ }
99
+ template <class F>
100
+ __m512i fwd_to_avx(F f, __m512i self, int32_t other)
101
+ {
102
+ __m256i self_low = lower_half(self), self_high = upper_half(self);
103
+ __m256i res_low = f(self_low, other);
104
+ __m256i res_high = f(self_high, other);
105
+ return merge_avx(res_low, res_high);
106
+ }
107
+ }
108
+ namespace detail
109
+ {
110
+
111
+ XSIMD_INLINE uint32_t morton(uint16_t x, uint16_t y) noexcept
112
+ {
113
+
114
+ static const unsigned short MortonTable256[256] = {
115
+ 0x0000, 0x0001, 0x0004, 0x0005, 0x0010, 0x0011, 0x0014, 0x0015,
116
+ 0x0040, 0x0041, 0x0044, 0x0045, 0x0050, 0x0051, 0x0054, 0x0055,
117
+ 0x0100, 0x0101, 0x0104, 0x0105, 0x0110, 0x0111, 0x0114, 0x0115,
118
+ 0x0140, 0x0141, 0x0144, 0x0145, 0x0150, 0x0151, 0x0154, 0x0155,
119
+ 0x0400, 0x0401, 0x0404, 0x0405, 0x0410, 0x0411, 0x0414, 0x0415,
120
+ 0x0440, 0x0441, 0x0444, 0x0445, 0x0450, 0x0451, 0x0454, 0x0455,
121
+ 0x0500, 0x0501, 0x0504, 0x0505, 0x0510, 0x0511, 0x0514, 0x0515,
122
+ 0x0540, 0x0541, 0x0544, 0x0545, 0x0550, 0x0551, 0x0554, 0x0555,
123
+ 0x1000, 0x1001, 0x1004, 0x1005, 0x1010, 0x1011, 0x1014, 0x1015,
124
+ 0x1040, 0x1041, 0x1044, 0x1045, 0x1050, 0x1051, 0x1054, 0x1055,
125
+ 0x1100, 0x1101, 0x1104, 0x1105, 0x1110, 0x1111, 0x1114, 0x1115,
126
+ 0x1140, 0x1141, 0x1144, 0x1145, 0x1150, 0x1151, 0x1154, 0x1155,
127
+ 0x1400, 0x1401, 0x1404, 0x1405, 0x1410, 0x1411, 0x1414, 0x1415,
128
+ 0x1440, 0x1441, 0x1444, 0x1445, 0x1450, 0x1451, 0x1454, 0x1455,
129
+ 0x1500, 0x1501, 0x1504, 0x1505, 0x1510, 0x1511, 0x1514, 0x1515,
130
+ 0x1540, 0x1541, 0x1544, 0x1545, 0x1550, 0x1551, 0x1554, 0x1555,
131
+ 0x4000, 0x4001, 0x4004, 0x4005, 0x4010, 0x4011, 0x4014, 0x4015,
132
+ 0x4040, 0x4041, 0x4044, 0x4045, 0x4050, 0x4051, 0x4054, 0x4055,
133
+ 0x4100, 0x4101, 0x4104, 0x4105, 0x4110, 0x4111, 0x4114, 0x4115,
134
+ 0x4140, 0x4141, 0x4144, 0x4145, 0x4150, 0x4151, 0x4154, 0x4155,
135
+ 0x4400, 0x4401, 0x4404, 0x4405, 0x4410, 0x4411, 0x4414, 0x4415,
136
+ 0x4440, 0x4441, 0x4444, 0x4445, 0x4450, 0x4451, 0x4454, 0x4455,
137
+ 0x4500, 0x4501, 0x4504, 0x4505, 0x4510, 0x4511, 0x4514, 0x4515,
138
+ 0x4540, 0x4541, 0x4544, 0x4545, 0x4550, 0x4551, 0x4554, 0x4555,
139
+ 0x5000, 0x5001, 0x5004, 0x5005, 0x5010, 0x5011, 0x5014, 0x5015,
140
+ 0x5040, 0x5041, 0x5044, 0x5045, 0x5050, 0x5051, 0x5054, 0x5055,
141
+ 0x5100, 0x5101, 0x5104, 0x5105, 0x5110, 0x5111, 0x5114, 0x5115,
142
+ 0x5140, 0x5141, 0x5144, 0x5145, 0x5150, 0x5151, 0x5154, 0x5155,
143
+ 0x5400, 0x5401, 0x5404, 0x5405, 0x5410, 0x5411, 0x5414, 0x5415,
144
+ 0x5440, 0x5441, 0x5444, 0x5445, 0x5450, 0x5451, 0x5454, 0x5455,
145
+ 0x5500, 0x5501, 0x5504, 0x5505, 0x5510, 0x5511, 0x5514, 0x5515,
146
+ 0x5540, 0x5541, 0x5544, 0x5545, 0x5550, 0x5551, 0x5554, 0x5555
147
+ };
148
+
149
+ uint32_t z = MortonTable256[y >> 8] << 17 | MortonTable256[x >> 8] << 16 | MortonTable256[y & 0xFF] << 1 | MortonTable256[x & 0xFF];
150
+ return z;
151
+ }
152
+
153
+ template <class A, class T, int Cmp>
154
+ XSIMD_INLINE batch_bool<T, A> compare_int_avx512f(batch<T, A> const& self, batch<T, A> const& other) noexcept
155
+ {
156
+ using register_type = typename batch_bool<T, A>::register_type;
157
+ if (std::is_signed<T>::value)
158
+ {
159
+ XSIMD_IF_CONSTEXPR(sizeof(T) == 1)
160
+ {
161
+ // shifting to take sign into account
162
+ uint64_t mask_low0 = _mm512_cmp_epi32_mask((batch<int32_t, A>(self.data) & batch<int32_t, A>(0x000000FF)) << 24,
163
+ (batch<int32_t, A>(other.data) & batch<int32_t, A>(0x000000FF)) << 24,
164
+ Cmp);
165
+ uint64_t mask_low1 = _mm512_cmp_epi32_mask((batch<int32_t, A>(self.data) & batch<int32_t, A>(0x0000FF00)) << 16,
166
+ (batch<int32_t, A>(other.data) & batch<int32_t, A>(0x0000FF00)) << 16,
167
+ Cmp);
168
+ uint64_t mask_high0 = _mm512_cmp_epi32_mask((batch<int32_t, A>(self.data) & batch<int32_t, A>(0x00FF0000)) << 8,
169
+ (batch<int32_t, A>(other.data) & batch<int32_t, A>(0x00FF0000)) << 8,
170
+ Cmp);
171
+ uint64_t mask_high1 = _mm512_cmp_epi32_mask((batch<int32_t, A>(self.data) & batch<int32_t, A>(0xFF000000)),
172
+ (batch<int32_t, A>(other.data) & batch<int32_t, A>(0xFF000000)),
173
+ Cmp);
174
+ uint64_t mask = 0;
175
+ for (unsigned i = 0; i < 16; ++i)
176
+ {
177
+ mask |= (mask_low0 & (uint64_t(1) << i)) << (3 * i + 0);
178
+ mask |= (mask_low1 & (uint64_t(1) << i)) << (3 * i + 1);
179
+ mask |= (mask_high0 & (uint64_t(1) << i)) << (3 * i + 2);
180
+ mask |= (mask_high1 & (uint64_t(1) << i)) << (3 * i + 3);
181
+ }
182
+ return (register_type)mask;
183
+ }
184
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 2)
185
+ {
186
+ // shifting to take sign into account
187
+ uint16_t mask_low = _mm512_cmp_epi32_mask((batch<int32_t, A>(self.data) & batch<int32_t, A>(0x0000FFFF)) << 16,
188
+ (batch<int32_t, A>(other.data) & batch<int32_t, A>(0x0000FFFF)) << 16,
189
+ Cmp);
190
+ uint16_t mask_high = _mm512_cmp_epi32_mask((batch<int32_t, A>(self.data) & batch<int32_t, A>(0xFFFF0000)),
191
+ (batch<int32_t, A>(other.data) & batch<int32_t, A>(0xFFFF0000)),
192
+ Cmp);
193
+ return static_cast<register_type>(morton(mask_low, mask_high));
194
+ }
195
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
196
+ {
197
+ return (register_type)_mm512_cmp_epi32_mask(self, other, Cmp);
198
+ }
199
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 8)
200
+ {
201
+ return (register_type)_mm512_cmp_epi64_mask(self, other, Cmp);
202
+ }
203
+ }
204
+ else
205
+ {
206
+ XSIMD_IF_CONSTEXPR(sizeof(T) == 1)
207
+ {
208
+ uint64_t mask_low0 = _mm512_cmp_epu32_mask((batch<uint32_t, A>(self.data) & batch<uint32_t, A>(0x000000FF)), (batch<uint32_t, A>(other.data) & batch<uint32_t, A>(0x000000FF)), Cmp);
209
+ uint64_t mask_low1 = _mm512_cmp_epu32_mask((batch<uint32_t, A>(self.data) & batch<uint32_t, A>(0x0000FF00)), (batch<uint32_t, A>(other.data) & batch<uint32_t, A>(0x0000FF00)), Cmp);
210
+ uint64_t mask_high0 = _mm512_cmp_epu32_mask((batch<uint32_t, A>(self.data) & batch<uint32_t, A>(0x00FF0000)), (batch<uint32_t, A>(other.data) & batch<uint32_t, A>(0x00FF0000)), Cmp);
211
+ uint64_t mask_high1 = _mm512_cmp_epu32_mask((batch<uint32_t, A>(self.data) & batch<uint32_t, A>(0xFF000000)), (batch<uint32_t, A>(other.data) & batch<uint32_t, A>(0xFF000000)), Cmp);
212
+ uint64_t mask = 0;
213
+ for (unsigned i = 0; i < 16; ++i)
214
+ {
215
+ mask |= (mask_low0 & (uint64_t(1) << i)) << (3 * i + 0);
216
+ mask |= (mask_low1 & (uint64_t(1) << i)) << (3 * i + 1);
217
+ mask |= (mask_high0 & (uint64_t(1) << i)) << (3 * i + 2);
218
+ mask |= (mask_high1 & (uint64_t(1) << i)) << (3 * i + 3);
219
+ }
220
+ return (register_type)mask;
221
+ }
222
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 2)
223
+ {
224
+ uint16_t mask_low = _mm512_cmp_epu32_mask((batch<uint32_t, A>(self.data) & batch<uint32_t, A>(0x0000FFFF)), (batch<uint32_t, A>(other.data) & batch<uint32_t, A>(0x0000FFFF)), Cmp);
225
+ uint16_t mask_high = _mm512_cmp_epu32_mask((batch<uint32_t, A>(self.data) & batch<uint32_t, A>(0xFFFF0000)), (batch<uint32_t, A>(other.data) & batch<uint32_t, A>(0xFFFF0000)), Cmp);
226
+ return static_cast<register_type>(morton(mask_low, mask_high));
227
+ }
228
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
229
+ {
230
+ return (register_type)_mm512_cmp_epu32_mask(self, other, Cmp);
231
+ }
232
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 8)
233
+ {
234
+ return (register_type)_mm512_cmp_epu64_mask(self, other, Cmp);
235
+ }
236
+ }
237
+ }
238
+ }
239
+
240
+ namespace detail
241
+ {
242
+ // --- compact unified helpers for masked loads/stores & zero-extension ---
243
+ struct high_tag
244
+ {
245
+ };
246
+
247
+ // zero-extend 256 -> 512 (low) and place-into-high variants
248
+ XSIMD_INLINE __m512i zero_extend(__m256i lo) noexcept { return _mm512_zextsi256_si512(lo); }
249
+ XSIMD_INLINE __m512 zero_extend(__m256 lo) noexcept { return _mm512_zextps256_ps512(lo); }
250
+ XSIMD_INLINE __m512d zero_extend(__m256d lo) noexcept { return _mm512_zextpd256_pd512(lo); }
251
+
252
+ XSIMD_INLINE __m512i zero_extend(__m256i hi, high_tag) noexcept { return _mm512_inserti64x4(_mm512_setzero_si512(), hi, 1); }
253
+ XSIMD_INLINE __m512 zero_extend(__m256 hi, high_tag) noexcept
254
+ {
255
+ return _mm512_castpd_ps(_mm512_insertf64x4(_mm512_castps_pd(_mm512_setzero_ps()), _mm256_castps_pd(hi), 1));
256
+ }
257
+ XSIMD_INLINE __m512d zero_extend(__m256d hi, high_tag) noexcept { return _mm512_insertf64x4(_mm512_setzero_pd(), hi, 1); }
258
+
259
+ // pointer-level masked loads (overloads by pointer/value size and alignment)
260
+ XSIMD_INLINE __m512 load_masked(const float* mem, uint64_t m, aligned_mode) noexcept { return _mm512_maskz_load_ps((__mmask16)m, mem); }
261
+ XSIMD_INLINE __m512 load_masked(const float* mem, uint64_t m, unaligned_mode) noexcept { return _mm512_maskz_loadu_ps((__mmask16)m, mem); }
262
+ XSIMD_INLINE __m512d load_masked(const double* mem, uint64_t m, aligned_mode) noexcept { return _mm512_maskz_load_pd((__mmask8)m, mem); }
263
+ XSIMD_INLINE __m512d load_masked(const double* mem, uint64_t m, unaligned_mode) noexcept { return _mm512_maskz_loadu_pd((__mmask8)m, mem); }
264
+
265
+ XSIMD_INLINE __m512i load_masked(const int32_t* mem, uint64_t m, aligned_mode) noexcept { return _mm512_maskz_load_epi32((__mmask16)m, mem); }
266
+ XSIMD_INLINE __m512i load_masked(const int32_t* mem, uint64_t m, unaligned_mode) noexcept { return _mm512_maskz_loadu_epi32((__mmask16)m, mem); }
267
+ XSIMD_INLINE __m512i load_masked(const uint32_t* mem, uint64_t m, aligned_mode) noexcept { return _mm512_maskz_load_epi32((__mmask16)m, reinterpret_cast<const int32_t*>(mem)); }
268
+ XSIMD_INLINE __m512i load_masked(const uint32_t* mem, uint64_t m, unaligned_mode) noexcept { return _mm512_maskz_loadu_epi32((__mmask16)m, reinterpret_cast<const int32_t*>(mem)); }
269
+
270
+ XSIMD_INLINE __m512i load_masked(const int64_t* mem, uint64_t m, aligned_mode) noexcept { return _mm512_maskz_load_epi64((__mmask8)m, mem); }
271
+ XSIMD_INLINE __m512i load_masked(const int64_t* mem, uint64_t m, unaligned_mode) noexcept { return _mm512_maskz_loadu_epi64((__mmask8)m, mem); }
272
+ XSIMD_INLINE __m512i load_masked(const uint64_t* mem, uint64_t m, aligned_mode) noexcept { return _mm512_maskz_load_epi64((__mmask8)m, reinterpret_cast<const int64_t*>(mem)); }
273
+ XSIMD_INLINE __m512i load_masked(const uint64_t* mem, uint64_t m, unaligned_mode) noexcept { return _mm512_maskz_loadu_epi64((__mmask8)m, reinterpret_cast<const int64_t*>(mem)); }
274
+
275
+ // Register-level AVX2-forward helpers: accept 256-bit halves and return 512-bit
276
+ XSIMD_INLINE __m512 load_masked(__m256 lo) noexcept { return zero_extend(lo); }
277
+ XSIMD_INLINE __m512d load_masked(__m256d lo) noexcept { return zero_extend(lo); }
278
+ XSIMD_INLINE __m512i load_masked(__m256i lo) noexcept { return zero_extend(lo); }
279
+ XSIMD_INLINE __m512 load_masked(__m256 hi, high_tag) noexcept { return zero_extend(hi, high_tag {}); }
280
+ XSIMD_INLINE __m512d load_masked(__m256d hi, high_tag) noexcept { return zero_extend(hi, high_tag {}); }
281
+ XSIMD_INLINE __m512i load_masked(__m256i hi, high_tag) noexcept { return zero_extend(hi, high_tag {}); }
282
+
283
+ // pointer-level masked stores (overloads by pointer/value size and alignment)
284
+ XSIMD_INLINE void store_masked(float* mem, __m512 src, uint64_t m, aligned_mode) noexcept { _mm512_mask_store_ps(mem, (__mmask16)m, src); }
285
+ XSIMD_INLINE void store_masked(float* mem, __m512 src, uint64_t m, unaligned_mode) noexcept { _mm512_mask_storeu_ps(mem, (__mmask16)m, src); }
286
+ XSIMD_INLINE void store_masked(double* mem, __m512d src, uint64_t m, aligned_mode) noexcept { _mm512_mask_store_pd(mem, (__mmask8)m, src); }
287
+ XSIMD_INLINE void store_masked(double* mem, __m512d src, uint64_t m, unaligned_mode) noexcept { _mm512_mask_storeu_pd(mem, (__mmask8)m, src); }
288
+
289
+ XSIMD_INLINE void store_masked(int32_t* mem, __m512i src, uint64_t m, aligned_mode) noexcept { _mm512_mask_store_epi32(mem, (__mmask16)m, src); }
290
+ XSIMD_INLINE void store_masked(int32_t* mem, __m512i src, uint64_t m, unaligned_mode) noexcept { _mm512_mask_storeu_epi32(mem, (__mmask16)m, src); }
291
+ XSIMD_INLINE void store_masked(uint32_t* mem, __m512i src, uint64_t m, aligned_mode) noexcept { _mm512_mask_store_epi32(reinterpret_cast<int32_t*>(mem), (__mmask16)m, src); }
292
+ XSIMD_INLINE void store_masked(uint32_t* mem, __m512i src, uint64_t m, unaligned_mode) noexcept { _mm512_mask_storeu_epi32(reinterpret_cast<int32_t*>(mem), (__mmask16)m, src); }
293
+
294
+ XSIMD_INLINE void store_masked(int64_t* mem, __m512i src, uint64_t m, aligned_mode) noexcept { _mm512_mask_store_epi64(mem, (__mmask8)m, src); }
295
+ XSIMD_INLINE void store_masked(int64_t* mem, __m512i src, uint64_t m, unaligned_mode) noexcept { _mm512_mask_storeu_epi64(mem, (__mmask8)m, src); }
296
+ XSIMD_INLINE void store_masked(uint64_t* mem, __m512i src, uint64_t m, aligned_mode) noexcept { _mm512_mask_store_epi64(reinterpret_cast<int64_t*>(mem), (__mmask8)m, src); }
297
+ XSIMD_INLINE void store_masked(uint64_t* mem, __m512i src, uint64_t m, unaligned_mode) noexcept { _mm512_mask_storeu_epi64(reinterpret_cast<int64_t*>(mem), (__mmask8)m, src); }
298
+
299
+ } // namespace detail
300
+
301
+ template <class A, class T, bool... Values, class Mode,
302
+ typename = std::enable_if_t<(sizeof(T) >= 4)>>
303
+ XSIMD_INLINE batch<T, A> load_masked(T const* mem,
304
+ batch_bool_constant<T, A, Values...> mask,
305
+ convert<T>, Mode, requires_arch<avx512f>) noexcept
306
+ {
307
+ constexpr auto half = batch<T, A>::size / 2;
308
+ XSIMD_IF_CONSTEXPR(mask.countl_zero() >= half) // lower-half AVX2 forwarding
309
+ {
310
+ constexpr auto mlo = ::xsimd::detail::lower_half<avx2>(mask);
311
+ const auto lo = load_masked<avx2>(mem, mlo, convert<T> {}, Mode {}, avx2 {});
312
+ return detail::load_masked(lo); // zero-extend low half
313
+ }
314
+ else XSIMD_IF_CONSTEXPR(mask.countr_zero() >= half) // upper-half AVX2 forwarding
315
+ {
316
+ constexpr auto mhi = ::xsimd::detail::upper_half<avx2>(mask);
317
+ const auto hi = load_masked<avx2>(mem + half, mhi, convert<T> {}, Mode {}, avx2 {});
318
+ return detail::load_masked(hi, detail::high_tag {});
319
+ }
320
+ else
321
+ {
322
+ // fallback to centralized pointer-level helper
323
+ return detail::load_masked(mem, mask.mask(), Mode {});
324
+ }
325
+ }
326
+
327
+ template <class A, class T, bool... Values, class Mode,
328
+ typename = std::enable_if_t<(sizeof(T) >= 4)>>
329
+ XSIMD_INLINE void store_masked(T* mem,
330
+ batch<T, A> const& src,
331
+ batch_bool_constant<T, A, Values...> mask,
332
+ Mode, requires_arch<avx512f>) noexcept
333
+ {
334
+ constexpr auto half = batch<T, A>::size / 2;
335
+ XSIMD_IF_CONSTEXPR(mask.countl_zero() >= half) // lower-half AVX2 forwarding
336
+ {
337
+ constexpr auto mlo = ::xsimd::detail::lower_half<avx2>(mask);
338
+ const auto lo = detail::lower_half(src);
339
+ store_masked<avx2>(mem, lo, mlo, Mode {}, avx2 {});
340
+ }
341
+ else XSIMD_IF_CONSTEXPR(mask.countr_zero() >= half) // upper-half AVX2 forwarding
342
+ {
343
+ constexpr auto mhi = ::xsimd::detail::upper_half<avx2>(mask);
344
+ const auto hi = detail::upper_half(src);
345
+ store_masked<avx2>(mem + half, hi, mhi, Mode {}, avx2 {});
346
+ }
347
+ else
348
+ {
349
+ // fallback to centralized pointer-level helper
350
+ detail::store_masked(mem, src, mask.mask(), Mode {});
351
+ }
352
+ }
353
+
354
+ // abs
355
+ template <class A>
356
+ XSIMD_INLINE batch<float, A> abs(batch<float, A> const& self, requires_arch<avx512f>) noexcept
357
+ {
358
+ __m512 self_asf = (__m512)self;
359
+ __m512i self_asi = *reinterpret_cast<__m512i*>(&self_asf);
360
+ __m512i res_asi = _mm512_and_epi32(_mm512_set1_epi32(0x7FFFFFFF), self_asi);
361
+ return *reinterpret_cast<__m512*>(&res_asi);
362
+ }
363
+ template <class A>
364
+ XSIMD_INLINE batch<double, A> abs(batch<double, A> const& self, requires_arch<avx512f>) noexcept
365
+ {
366
+ __m512d self_asd = (__m512d)self;
367
+ __m512i self_asi = *reinterpret_cast<__m512i*>(&self_asd);
368
+ __m512i res_asi = _mm512_and_epi64(_mm512_set1_epi64(0x7FFFFFFFFFFFFFFF),
369
+ self_asi);
370
+ return *reinterpret_cast<__m512d*>(&res_asi);
371
+ }
372
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
373
+ XSIMD_INLINE batch<T, A> abs(batch<T, A> const& self, requires_arch<avx512f>) noexcept
374
+ {
375
+ if (std::is_unsigned<T>::value)
376
+ {
377
+ return self;
378
+ }
379
+
380
+ XSIMD_IF_CONSTEXPR(sizeof(T) == 1)
381
+ {
382
+ return detail::fwd_to_avx([](__m256i s) noexcept
383
+ { return abs(batch<T, avx2>(s)); },
384
+ self);
385
+ }
386
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 2)
387
+ {
388
+ return detail::fwd_to_avx([](__m256i s) noexcept
389
+ { return abs(batch<T, avx2>(s)); },
390
+ self);
391
+ }
392
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
393
+ {
394
+ return _mm512_abs_epi32(self);
395
+ }
396
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 8)
397
+ {
398
+ return _mm512_abs_epi64(self);
399
+ }
400
+ else
401
+ {
402
+ assert(false && "unsupported arch/op combination");
403
+ return {};
404
+ }
405
+ }
406
+
407
+ // add
408
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
409
+ XSIMD_INLINE batch<T, A> add(batch<T, A> const& self, batch<T, A> const& other, requires_arch<avx512f>) noexcept
410
+ {
411
+ XSIMD_IF_CONSTEXPR(sizeof(T) == 1)
412
+ {
413
+ return detail::fwd_to_avx([](__m256i s, __m256i o) noexcept
414
+ { return add(batch<T, avx2>(s), batch<T, avx2>(o)); },
415
+ self, other);
416
+ }
417
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 2)
418
+ {
419
+ return detail::fwd_to_avx([](__m256i s, __m256i o) noexcept
420
+ { return add(batch<T, avx2>(s), batch<T, avx2>(o)); },
421
+ self, other);
422
+ }
423
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
424
+ {
425
+ return _mm512_add_epi32(self, other);
426
+ }
427
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 8)
428
+ {
429
+ return _mm512_add_epi64(self, other);
430
+ }
431
+ else
432
+ {
433
+ assert(false && "unsupported arch/op combination");
434
+ return {};
435
+ }
436
+ }
437
+ template <class A>
438
+ XSIMD_INLINE batch<float, A> add(batch<float, A> const& self, batch<float, A> const& other, requires_arch<avx512f>) noexcept
439
+ {
440
+ return _mm512_add_ps(self, other);
441
+ }
442
+ template <class A>
443
+ XSIMD_INLINE batch<double, A> add(batch<double, A> const& self, batch<double, A> const& other, requires_arch<avx512f>) noexcept
444
+ {
445
+ return _mm512_add_pd(self, other);
446
+ }
447
+
448
+ // all
449
+ template <class A, class T>
450
+ XSIMD_INLINE bool all(batch_bool<T, A> const& self, requires_arch<avx512f>) noexcept
451
+ {
452
+ using register_type = typename batch_bool<T, A>::register_type;
453
+ return self.data == register_type(-1);
454
+ }
455
+
456
+ // any
457
+ template <class A, class T>
458
+ XSIMD_INLINE bool any(batch_bool<T, A> const& self, requires_arch<avx512f>) noexcept
459
+ {
460
+ using register_type = typename batch_bool<T, A>::register_type;
461
+ return self.data != register_type(0);
462
+ }
463
+
464
+ // batch_bool_cast
465
+ template <class A, class T_out, class T_in>
466
+ XSIMD_INLINE batch_bool<T_out, A> batch_bool_cast(batch_bool<T_in, A> const& self, batch_bool<T_out, A> const&, requires_arch<avx512f>) noexcept
467
+ {
468
+ return self.data;
469
+ }
470
+
471
+ // bitwise_and
472
+ template <class A>
473
+ XSIMD_INLINE batch<float, A> bitwise_and(batch<float, A> const& self, batch<float, A> const& other, requires_arch<avx512f>) noexcept
474
+ {
475
+ #if defined(_MSC_VER)
476
+ return _mm512_and_ps(self, other);
477
+ #else
478
+ return _mm512_castsi512_ps(_mm512_and_si512(_mm512_castps_si512(self), _mm512_castps_si512(other)));
479
+ #endif
480
+ }
481
+ template <class A>
482
+ XSIMD_INLINE batch<double, A> bitwise_and(batch<double, A> const& self, batch<double, A> const& other, requires_arch<avx512f>) noexcept
483
+ {
484
+ return _mm512_castsi512_pd(_mm512_and_si512(_mm512_castpd_si512(self), _mm512_castpd_si512(other)));
485
+ }
486
+
487
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
488
+ XSIMD_INLINE batch<T, A> bitwise_and(batch<T, A> const& self, batch<T, A> const& other, requires_arch<avx512f>) noexcept
489
+ {
490
+ return _mm512_and_si512(self, other);
491
+ }
492
+
493
+ template <class A, class T>
494
+ XSIMD_INLINE batch_bool<T, A> bitwise_and(batch_bool<T, A> const& self, batch_bool<T, A> const& other, requires_arch<avx512f>) noexcept
495
+ {
496
+ using register_type = typename batch_bool<T, A>::register_type;
497
+ return register_type(self.data & other.data);
498
+ }
499
+
500
+ // bitwise_andnot
501
+ template <class A>
502
+ XSIMD_INLINE batch<float, A> bitwise_andnot(batch<float, A> const& self, batch<float, A> const& other, requires_arch<avx512f>) noexcept
503
+ {
504
+ return _mm512_castsi512_ps(_mm512_andnot_si512(_mm512_castps_si512(other), _mm512_castps_si512(self)));
505
+ }
506
+ template <class A>
507
+ XSIMD_INLINE batch<double, A> bitwise_andnot(batch<double, A> const& self, batch<double, A> const& other, requires_arch<avx512f>) noexcept
508
+ {
509
+ return _mm512_castsi512_pd(_mm512_andnot_si512(_mm512_castpd_si512(other), _mm512_castpd_si512(self)));
510
+ }
511
+
512
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
513
+ XSIMD_INLINE batch<T, A> bitwise_andnot(batch<T, A> const& self, batch<T, A> const& other, requires_arch<avx512f>) noexcept
514
+ {
515
+ return _mm512_andnot_si512(other, self);
516
+ }
517
+
518
+ template <class A, class T>
519
+ XSIMD_INLINE batch_bool<T, A> bitwise_andnot(batch_bool<T, A> const& self, batch_bool<T, A> const& other, requires_arch<avx512f>) noexcept
520
+ {
521
+ using register_type = typename batch_bool<T, A>::register_type;
522
+ return register_type(self.data & ~other.data);
523
+ }
524
+
525
+ // bitwise_lshift
526
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
527
+ XSIMD_INLINE batch<T, A> bitwise_lshift(batch<T, A> const& self, int32_t other, requires_arch<avx512f>) noexcept
528
+ {
529
+ XSIMD_IF_CONSTEXPR(sizeof(T) == 1)
530
+ {
531
+ #if defined(XSIMD_AVX512_SHIFT_INTRINSICS_IMM_ONLY)
532
+ __m512i tmp = _mm512_sllv_epi32(self, _mm512_set1_epi32(other));
533
+ #else
534
+ __m512i tmp = _mm512_slli_epi32(self, other);
535
+ #endif
536
+ return _mm512_and_si512(_mm512_set1_epi8(0xFF << other), tmp);
537
+ }
538
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 2)
539
+ {
540
+ return detail::fwd_to_avx([](__m256i s, int32_t o) noexcept
541
+ { return bitwise_lshift(batch<T, avx2>(s), o, avx2 {}); },
542
+ self, other);
543
+ #if defined(XSIMD_AVX512_SHIFT_INTRINSICS_IMM_ONLY)
544
+ }
545
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
546
+ {
547
+ return _mm512_sllv_epi32(self, _mm512_set1_epi32(other));
548
+ }
549
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 8)
550
+ {
551
+ return _mm512_sllv_epi64(self, _mm512_set1_epi64(other));
552
+ #else
553
+ }
554
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
555
+ {
556
+ return _mm512_slli_epi32(self, other);
557
+ }
558
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 8)
559
+ {
560
+ return _mm512_slli_epi64(self, other);
561
+ #endif
562
+ }
563
+ else
564
+ {
565
+ assert(false && "unsupported arch/op combination");
566
+ return {};
567
+ }
568
+ }
569
+
570
+ // bitwise_not
571
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
572
+ XSIMD_INLINE batch<T, A> bitwise_not(batch<T, A> const& self, requires_arch<avx512f>) noexcept
573
+ {
574
+ return _mm512_xor_si512(self, _mm512_set1_epi32(-1));
575
+ }
576
+ template <class A, class T>
577
+ XSIMD_INLINE batch_bool<T, A> bitwise_not(batch_bool<T, A> const& self, requires_arch<avx512f>) noexcept
578
+ {
579
+ using register_type = typename batch_bool<T, A>::register_type;
580
+ return register_type(~self.data);
581
+ }
582
+
583
+ template <class A>
584
+ XSIMD_INLINE batch<float, A> bitwise_not(batch<float, A> const& self, requires_arch<avx512f>) noexcept
585
+ {
586
+ return _mm512_castsi512_ps(_mm512_xor_si512(_mm512_castps_si512(self), _mm512_set1_epi32(-1)));
587
+ }
588
+ template <class A>
589
+ XSIMD_INLINE batch<double, A> bitwise_not(batch<double, A> const& self, requires_arch<avx512f>) noexcept
590
+ {
591
+ return _mm512_castsi512_pd(_mm512_xor_si512(_mm512_castpd_si512(self), _mm512_set1_epi32(-1)));
592
+ }
593
+
594
+ // bitwise_or
595
+ template <class A>
596
+ XSIMD_INLINE batch<float, A> bitwise_or(batch<float, A> const& self, batch<float, A> const& other, requires_arch<avx512f>) noexcept
597
+ {
598
+ return _mm512_castsi512_ps(_mm512_or_si512(_mm512_castps_si512(self), _mm512_castps_si512(other)));
599
+ }
600
+ template <class A>
601
+ XSIMD_INLINE batch<double, A> bitwise_or(batch<double, A> const& self, batch<double, A> const& other, requires_arch<avx512f>) noexcept
602
+ {
603
+ return _mm512_castsi512_pd(_mm512_or_si512(_mm512_castpd_si512(self), _mm512_castpd_si512(other)));
604
+ }
605
+
606
+ template <class A, class T>
607
+ XSIMD_INLINE batch_bool<T, A> bitwise_or(batch_bool<T, A> const& self, batch_bool<T, A> const& other, requires_arch<avx512f>) noexcept
608
+ {
609
+ using register_type = typename batch_bool<T, A>::register_type;
610
+ return register_type(self.data | other.data);
611
+ }
612
+
613
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
614
+ XSIMD_INLINE batch<T, A> bitwise_or(batch<T, A> const& self, batch<T, A> const& other, requires_arch<avx512f>) noexcept
615
+ {
616
+ return _mm512_or_si512(self, other);
617
+ }
618
+
619
+ // bitwise_rshift
620
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
621
+ XSIMD_INLINE batch<T, A> bitwise_rshift(batch<T, A> const& self, int32_t other, requires_arch<avx512f>) noexcept
622
+ {
623
+ if (std::is_signed<T>::value)
624
+ {
625
+ #if defined(XSIMD_AVX512_SHIFT_INTRINSICS_IMM_ONLY)
626
+ XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
627
+ {
628
+ return _mm512_srav_epi32(self, _mm512_set1_epi32(other));
629
+ }
630
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 8)
631
+ {
632
+ return _mm512_srav_epi64(self, _mm512_set1_epi64(other));
633
+ #else
634
+ XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
635
+ {
636
+ return _mm512_srai_epi32(self, other);
637
+ }
638
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 8)
639
+ {
640
+ return _mm512_srai_epi64(self, other);
641
+ #endif
642
+ }
643
+ else
644
+ {
645
+ return detail::fwd_to_avx([](__m256i s, int32_t o) noexcept
646
+ { return bitwise_rshift(batch<T, avx2>(s), o, avx2 {}); },
647
+ self, other);
648
+ }
649
+ }
650
+ else
651
+ {
652
+ XSIMD_IF_CONSTEXPR(sizeof(T) == 1)
653
+ {
654
+ #if defined(XSIMD_AVX512_SHIFT_INTRINSICS_IMM_ONLY)
655
+ __m512i tmp = _mm512_srlv_epi32(self, _mm512_set1_epi32(other));
656
+ #else
657
+ __m512i tmp = _mm512_srli_epi32(self, other);
658
+ #endif
659
+ return _mm512_and_si512(_mm512_set1_epi8(0xFF >> other), tmp);
660
+ #if defined(XSIMD_AVX512_SHIFT_INTRINSICS_IMM_ONLY)
661
+ }
662
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
663
+ {
664
+ return _mm512_srlv_epi32(self, _mm512_set1_epi32(other));
665
+ }
666
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 8)
667
+ {
668
+ return _mm512_srlv_epi64(self, _mm512_set1_epi64(other));
669
+ #else
670
+ }
671
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
672
+ {
673
+ return _mm512_srli_epi32(self, other);
674
+ }
675
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 8)
676
+ {
677
+ return _mm512_srli_epi64(self, other);
678
+ #endif
679
+ }
680
+ else
681
+ {
682
+ return detail::fwd_to_avx([](__m256i s, int32_t o) noexcept
683
+ { return bitwise_rshift(batch<T, avx2>(s), o, avx2 {}); },
684
+ self, other);
685
+ }
686
+ }
687
+ }
688
+
689
+ // rotl
690
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
691
+ XSIMD_INLINE batch<T, A> rotl(batch<T, A> const& self, batch<T, A> const& other, requires_arch<avx512f>) noexcept
692
+ {
693
+ XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
694
+ {
695
+ return _mm512_rolv_epi32(self, other);
696
+ }
697
+ XSIMD_IF_CONSTEXPR(sizeof(T) == 8)
698
+ {
699
+ return _mm512_rolv_epi64(self, other);
700
+ }
701
+ return detail::fwd_to_avx([](__m256i s, __m256i o) noexcept
702
+ { return rotl(batch<T, avx2>(s), batch<T, avx2>(o), avx2 {}); },
703
+ self, other);
704
+ }
705
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
706
+ XSIMD_INLINE batch<T, A> rotl(batch<T, A> const& self, int32_t other, requires_arch<avx512f>) noexcept
707
+ {
708
+ return rotl(self, batch<T, A>(other), A {});
709
+ }
710
+ template <size_t count, class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
711
+ XSIMD_INLINE batch<T, A> rotl(batch<T, A> const& self, requires_arch<avx512f>) noexcept
712
+ {
713
+ constexpr auto bits = std::numeric_limits<T>::digits + std::numeric_limits<T>::is_signed;
714
+ static_assert(count < bits, "Count must be less than the number of bits in T");
715
+ XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
716
+ {
717
+ return _mm512_rol_epi32(self, count);
718
+ }
719
+ XSIMD_IF_CONSTEXPR(sizeof(T) == 8)
720
+ {
721
+ return _mm512_rol_epi64(self, count);
722
+ }
723
+
724
+ return detail::fwd_to_avx([](__m256i s) noexcept
725
+ { return rotl<count>(batch<T, avx2>(s), avx2 {}); },
726
+ self);
727
+ }
728
+
729
+ // rotr
730
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
731
+ XSIMD_INLINE batch<T, A> rotr(batch<T, A> const& self, batch<T, A> const& other, requires_arch<avx512f>) noexcept
732
+ {
733
+ XSIMD_IF_CONSTEXPR(sizeof(T) < 4)
734
+ {
735
+ return detail::fwd_to_avx([](__m256i s, __m256i o) noexcept
736
+ { return rotr(batch<T, avx2>(s), batch<T, avx2>(o), avx2 {}); },
737
+ self, other);
738
+ }
739
+ XSIMD_IF_CONSTEXPR(std::is_unsigned<T>::value)
740
+ {
741
+ XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
742
+ {
743
+ return _mm512_rorv_epi32(self, other);
744
+ }
745
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 8)
746
+ {
747
+ return _mm512_rorv_epi64(self, other);
748
+ }
749
+ }
750
+ return rotr(self, other, common {});
751
+ }
752
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
753
+ XSIMD_INLINE batch<T, A> rotr(batch<T, A> const& self, int32_t other, requires_arch<avx512f>) noexcept
754
+ {
755
+ return rotr(self, batch<T, A>(other), A {});
756
+ }
757
+
758
+ template <size_t count, class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
759
+ XSIMD_INLINE batch<T, A> rotr(batch<T, A> const& self, requires_arch<avx512f>) noexcept
760
+ {
761
+ constexpr auto bits = std::numeric_limits<T>::digits + std::numeric_limits<T>::is_signed;
762
+ static_assert(count < bits, "Count must be less than the number of bits in T");
763
+ XSIMD_IF_CONSTEXPR(sizeof(T) < 4)
764
+ {
765
+ return detail::fwd_to_avx([](__m256i s) noexcept
766
+ { return rotr<count>(batch<T, avx2>(s), avx2 {}); },
767
+ self);
768
+ }
769
+ XSIMD_IF_CONSTEXPR(std::is_unsigned<T>::value)
770
+ {
771
+ XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
772
+ {
773
+ return _mm512_ror_epi32(self, count);
774
+ }
775
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 8)
776
+ {
777
+ return _mm512_ror_epi64(self, count);
778
+ }
779
+ }
780
+ return rotr<count>(self, common {});
781
+ }
782
+
783
+ // bitwise_xor
784
+ template <class A>
785
+ XSIMD_INLINE batch<float, A> bitwise_xor(batch<float, A> const& self, batch<float, A> const& other, requires_arch<avx512f>) noexcept
786
+ {
787
+ return _mm512_castsi512_ps(_mm512_xor_si512(_mm512_castps_si512(self), _mm512_castps_si512(other)));
788
+ }
789
+ template <class A>
790
+ XSIMD_INLINE batch<double, A> bitwise_xor(batch<double, A> const& self, batch<double, A> const& other, requires_arch<avx512f>) noexcept
791
+ {
792
+ return _mm512_castsi512_pd(_mm512_xor_si512(_mm512_castpd_si512(self), _mm512_castpd_si512(other)));
793
+ }
794
+
795
+ template <class A, class T>
796
+ XSIMD_INLINE batch_bool<T, A> bitwise_xor(batch_bool<T, A> const& self, batch_bool<T, A> const& other, requires_arch<avx512f>) noexcept
797
+ {
798
+ using register_type = typename batch_bool<T, A>::register_type;
799
+ return register_type(self.data ^ other.data);
800
+ }
801
+
802
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
803
+ XSIMD_INLINE batch<T, A> bitwise_xor(batch<T, A> const& self, batch<T, A> const& other, requires_arch<avx512f>) noexcept
804
+ {
805
+ return _mm512_xor_si512(self, other);
806
+ }
807
+
808
+ // bitwise_cast
809
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
810
+ XSIMD_INLINE batch<float, A> bitwise_cast(batch<T, A> const& self, batch<float, A> const&, requires_arch<avx512f>) noexcept
811
+ {
812
+ return _mm512_castsi512_ps(self);
813
+ }
814
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
815
+ XSIMD_INLINE batch<double, A> bitwise_cast(batch<T, A> const& self, batch<double, A> const&, requires_arch<avx512f>) noexcept
816
+ {
817
+ return _mm512_castsi512_pd(self);
818
+ }
819
+ template <class A, class T, class Tp, class = std::enable_if_t<std::is_integral<std::common_type_t<T, Tp>>::value>>
820
+ XSIMD_INLINE batch<Tp, A> bitwise_cast(batch<T, A> const& self, batch<Tp, A> const&, requires_arch<avx512f>) noexcept
821
+ {
822
+ return batch<Tp, A>(self.data);
823
+ }
824
+ template <class A>
825
+ XSIMD_INLINE batch<double, A> bitwise_cast(batch<float, A> const& self, batch<double, A> const&, requires_arch<avx512f>) noexcept
826
+ {
827
+ return _mm512_castps_pd(self);
828
+ }
829
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
830
+ XSIMD_INLINE batch<T, A> bitwise_cast(batch<float, A> const& self, batch<T, A> const&, requires_arch<avx512f>) noexcept
831
+ {
832
+ return _mm512_castps_si512(self);
833
+ }
834
+ template <class A>
835
+ XSIMD_INLINE batch<float, A> bitwise_cast(batch<double, A> const& self, batch<float, A> const&, requires_arch<avx512f>) noexcept
836
+ {
837
+ return _mm512_castpd_ps(self);
838
+ }
839
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
840
+ XSIMD_INLINE batch<T, A> bitwise_cast(batch<double, A> const& self, batch<T, A> const&, requires_arch<avx512f>) noexcept
841
+ {
842
+ return _mm512_castpd_si512(self);
843
+ }
844
+
845
+ // broadcast
846
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
847
+ XSIMD_INLINE batch<T, A> broadcast(T val, requires_arch<avx512f>) noexcept
848
+ {
849
+ XSIMD_IF_CONSTEXPR(sizeof(T) == 1)
850
+ {
851
+ return _mm512_set1_epi8(val);
852
+ }
853
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 2)
854
+ {
855
+ return _mm512_set1_epi16(val);
856
+ }
857
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
858
+ {
859
+ return _mm512_set1_epi32(val);
860
+ }
861
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 8)
862
+ {
863
+ return _mm512_set1_epi64(val);
864
+ }
865
+ else
866
+ {
867
+ assert(false && "unsupported");
868
+ return {};
869
+ }
870
+ }
871
+ template <class A>
872
+ XSIMD_INLINE batch<float, A> broadcast(float val, requires_arch<avx512f>) noexcept
873
+ {
874
+ return _mm512_set1_ps(val);
875
+ }
876
+ template <class A>
877
+ batch<double, A> XSIMD_INLINE broadcast(double val, requires_arch<avx512f>) noexcept
878
+ {
879
+ return _mm512_set1_pd(val);
880
+ }
881
+
882
+ // ceil
883
+ template <class A>
884
+ XSIMD_INLINE batch<float, A> ceil(batch<float, A> const& self, requires_arch<avx512f>) noexcept
885
+ {
886
+ return _mm512_roundscale_ps(self, _MM_FROUND_TO_POS_INF);
887
+ }
888
+ template <class A>
889
+ XSIMD_INLINE batch<double, A> ceil(batch<double, A> const& self, requires_arch<avx512f>) noexcept
890
+ {
891
+ return _mm512_roundscale_pd(self, _MM_FROUND_TO_POS_INF);
892
+ }
893
+
894
+ // compress
895
+ template <class A>
896
+ XSIMD_INLINE batch<float, A> compress(batch<float, A> const& self, batch_bool<float, A> const& mask, requires_arch<avx512f>) noexcept
897
+ {
898
+ return _mm512_maskz_compress_ps(mask.mask(), self);
899
+ }
900
+ template <class A>
901
+ XSIMD_INLINE batch<double, A> compress(batch<double, A> const& self, batch_bool<double, A> const& mask, requires_arch<avx512f>) noexcept
902
+ {
903
+ return _mm512_maskz_compress_pd(mask.mask(), self);
904
+ }
905
+ template <class A>
906
+ XSIMD_INLINE batch<int32_t, A> compress(batch<int32_t, A> const& self, batch_bool<int32_t, A> const& mask, requires_arch<avx512f>) noexcept
907
+ {
908
+ return _mm512_maskz_compress_epi32(mask.mask(), self);
909
+ }
910
+ template <class A>
911
+ XSIMD_INLINE batch<uint32_t, A> compress(batch<uint32_t, A> const& self, batch_bool<uint32_t, A> const& mask, requires_arch<avx512f>) noexcept
912
+ {
913
+ return _mm512_maskz_compress_epi32(mask.mask(), self);
914
+ }
915
+ template <class A>
916
+ XSIMD_INLINE batch<int64_t, A> compress(batch<int64_t, A> const& self, batch_bool<int64_t, A> const& mask, requires_arch<avx512f>) noexcept
917
+ {
918
+ return _mm512_maskz_compress_epi64(mask.mask(), self);
919
+ }
920
+ template <class A>
921
+ XSIMD_INLINE batch<uint64_t, A> compress(batch<uint64_t, A> const& self, batch_bool<uint64_t, A> const& mask, requires_arch<avx512f>) noexcept
922
+ {
923
+ return _mm512_maskz_compress_epi64(mask.mask(), self);
924
+ }
925
+
926
+ // convert
927
+ namespace detail
928
+ {
929
+ template <class A>
930
+ XSIMD_INLINE batch<float, A> fast_cast(batch<int32_t, A> const& self, batch<float, A> const&, requires_arch<avx512f>) noexcept
931
+ {
932
+ return _mm512_cvtepi32_ps(self);
933
+ }
934
+
935
+ template <class A>
936
+ XSIMD_INLINE batch<int32_t, A> fast_cast(batch<float, A> const& self, batch<int32_t, A> const&, requires_arch<avx512f>) noexcept
937
+ {
938
+ return _mm512_cvttps_epi32(self);
939
+ }
940
+
941
+ template <class A>
942
+ XSIMD_INLINE batch<float, A> fast_cast(batch<uint32_t, A> const& self, batch<float, A> const&, requires_arch<avx512f>) noexcept
943
+ {
944
+ return _mm512_cvtepu32_ps(self);
945
+ }
946
+
947
+ template <class A>
948
+ batch<uint32_t, A> fast_cast(batch<float, A> const& self, batch<uint32_t, A> const&, requires_arch<avx512f>)
949
+ {
950
+ return _mm512_cvttps_epu32(self);
951
+ }
952
+ }
953
+
954
+ namespace detail
955
+ {
956
+ // complex_low
957
+ template <class A>
958
+ XSIMD_INLINE batch<float, A> complex_low(batch<std::complex<float>, A> const& self, requires_arch<avx512f>) noexcept
959
+ {
960
+ __m512i idx = _mm512_setr_epi32(0, 16, 1, 17, 2, 18, 3, 19, 4, 20, 5, 21, 6, 22, 7, 23);
961
+ return _mm512_permutex2var_ps(self.real(), idx, self.imag());
962
+ }
963
+ template <class A>
964
+ XSIMD_INLINE batch<double, A> complex_low(batch<std::complex<double>, A> const& self, requires_arch<avx512f>) noexcept
965
+ {
966
+ __m512i idx = _mm512_setr_epi64(0, 8, 1, 9, 2, 10, 3, 11);
967
+ return _mm512_permutex2var_pd(self.real(), idx, self.imag());
968
+ }
969
+
970
+ // complex_high
971
+ template <class A>
972
+ XSIMD_INLINE batch<float, A> complex_high(batch<std::complex<float>, A> const& self, requires_arch<avx512f>) noexcept
973
+ {
974
+ __m512i idx = _mm512_setr_epi32(8, 24, 9, 25, 10, 26, 11, 27, 12, 28, 13, 29, 14, 30, 15, 31);
975
+ return _mm512_permutex2var_ps(self.real(), idx, self.imag());
976
+ }
977
+ template <class A>
978
+ XSIMD_INLINE batch<double, A> complex_high(batch<std::complex<double>, A> const& self, requires_arch<avx512f>) noexcept
979
+ {
980
+ __m512i idx = _mm512_setr_epi64(4, 12, 5, 13, 6, 14, 7, 15);
981
+ return _mm512_permutex2var_pd(self.real(), idx, self.imag());
982
+ }
983
+ }
984
+ // incr_if
985
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
986
+ XSIMD_INLINE batch<T, A> decr_if(batch<T, A> const& self, batch_bool<T, A> const& mask, requires_arch<avx512f>) noexcept
987
+ {
988
+
989
+ XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
990
+ {
991
+ return _mm512_mask_sub_epi32(self, mask.data, self, _mm512_set1_epi32(1));
992
+ }
993
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 8)
994
+ {
995
+ return _mm512_mask_sub_epi64(self, mask.data, self, _mm512_set1_epi64(1));
996
+ }
997
+ else
998
+ {
999
+ return decr_if(self, mask, common {});
1000
+ }
1001
+ }
1002
+
1003
+ // div
1004
+ template <class A>
1005
+ XSIMD_INLINE batch<float, A> div(batch<float, A> const& self, batch<float, A> const& other, requires_arch<avx512f>) noexcept
1006
+ {
1007
+ return _mm512_div_ps(self, other);
1008
+ }
1009
+ template <class A>
1010
+ XSIMD_INLINE batch<double, A> div(batch<double, A> const& self, batch<double, A> const& other, requires_arch<avx512f>) noexcept
1011
+ {
1012
+ return _mm512_div_pd(self, other);
1013
+ }
1014
+
1015
+ // eq
1016
+ template <class A>
1017
+ XSIMD_INLINE batch_bool<float, A> eq(batch<float, A> const& self, batch<float, A> const& other, requires_arch<avx512f>) noexcept
1018
+ {
1019
+ return _mm512_cmp_ps_mask(self, other, _CMP_EQ_OQ);
1020
+ }
1021
+ template <class A>
1022
+ XSIMD_INLINE batch_bool<double, A> eq(batch<double, A> const& self, batch<double, A> const& other, requires_arch<avx512f>) noexcept
1023
+ {
1024
+ return _mm512_cmp_pd_mask(self, other, _CMP_EQ_OQ);
1025
+ }
1026
+
1027
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
1028
+ XSIMD_INLINE batch_bool<T, A> eq(batch<T, A> const& self, batch<T, A> const& other, requires_arch<avx512f>) noexcept
1029
+ {
1030
+ return detail::compare_int_avx512f<A, T, _MM_CMPINT_EQ>(self, other);
1031
+ }
1032
+ template <class A, class T>
1033
+ XSIMD_INLINE batch_bool<T, A> eq(batch_bool<T, A> const& self, batch_bool<T, A> const& other, requires_arch<avx512f>) noexcept
1034
+ {
1035
+ using register_type = typename batch_bool<T, A>::register_type;
1036
+ return register_type(~self.data ^ other.data);
1037
+ }
1038
+
1039
+ // expand
1040
+ template <class A>
1041
+ XSIMD_INLINE batch<float, A> expand(batch<float, A> const& self, batch_bool<float, A> const& mask, requires_arch<avx512f>) noexcept
1042
+ {
1043
+ return _mm512_maskz_expand_ps(mask.mask(), self);
1044
+ }
1045
+ template <class A>
1046
+ XSIMD_INLINE batch<double, A> expand(batch<double, A> const& self, batch_bool<double, A> const& mask, requires_arch<avx512f>) noexcept
1047
+ {
1048
+ return _mm512_maskz_expand_pd(mask.mask(), self);
1049
+ }
1050
+ template <class A>
1051
+ XSIMD_INLINE batch<int32_t, A> expand(batch<int32_t, A> const& self, batch_bool<int32_t, A> const& mask, requires_arch<avx512f>) noexcept
1052
+ {
1053
+ return _mm512_maskz_expand_epi32(mask.mask(), self);
1054
+ }
1055
+ template <class A>
1056
+ XSIMD_INLINE batch<uint32_t, A> expand(batch<uint32_t, A> const& self, batch_bool<uint32_t, A> const& mask, requires_arch<avx512f>) noexcept
1057
+ {
1058
+ return _mm512_maskz_expand_epi32(mask.mask(), self);
1059
+ }
1060
+ template <class A>
1061
+ XSIMD_INLINE batch<int64_t, A> expand(batch<int64_t, A> const& self, batch_bool<int64_t, A> const& mask, requires_arch<avx512f>) noexcept
1062
+ {
1063
+ return _mm512_maskz_expand_epi64(mask.mask(), self);
1064
+ }
1065
+ template <class A>
1066
+ XSIMD_INLINE batch<uint64_t, A> expand(batch<uint64_t, A> const& self, batch_bool<uint64_t, A> const& mask, requires_arch<avx512f>) noexcept
1067
+ {
1068
+ return _mm512_maskz_expand_epi64(mask.mask(), self);
1069
+ }
1070
+
1071
+ // floor
1072
+ template <class A>
1073
+ XSIMD_INLINE batch<float, A> floor(batch<float, A> const& self, requires_arch<avx512f>) noexcept
1074
+ {
1075
+ return _mm512_roundscale_ps(self, _MM_FROUND_TO_NEG_INF);
1076
+ }
1077
+ template <class A>
1078
+ XSIMD_INLINE batch<double, A> floor(batch<double, A> const& self, requires_arch<avx512f>) noexcept
1079
+ {
1080
+ return _mm512_roundscale_pd(self, _MM_FROUND_TO_NEG_INF);
1081
+ }
1082
+
1083
+ // fnma
1084
+ template <class A>
1085
+ XSIMD_INLINE batch<float, A> fnma(batch<float, A> const& x, batch<float, A> const& y, batch<float, A> const& z, requires_arch<avx512f>) noexcept
1086
+ {
1087
+ return _mm512_fnmadd_ps(x, y, z);
1088
+ }
1089
+
1090
+ template <class A>
1091
+ XSIMD_INLINE batch<double, A> fnma(batch<double, A> const& x, batch<double, A> const& y, batch<double, A> const& z, requires_arch<avx512f>) noexcept
1092
+ {
1093
+ return _mm512_fnmadd_pd(x, y, z);
1094
+ }
1095
+
1096
+ // fma
1097
+ template <class A>
1098
+ XSIMD_INLINE batch<float, A> fma(batch<float, A> const& x, batch<float, A> const& y, batch<float, A> const& z, requires_arch<avx512f>) noexcept
1099
+ {
1100
+ return _mm512_fmadd_ps(x, y, z);
1101
+ }
1102
+
1103
+ template <class A>
1104
+ XSIMD_INLINE batch<double, A> fma(batch<double, A> const& x, batch<double, A> const& y, batch<double, A> const& z, requires_arch<avx512f>) noexcept
1105
+ {
1106
+ return _mm512_fmadd_pd(x, y, z);
1107
+ }
1108
+
1109
+ // fms
1110
+ template <class A>
1111
+ XSIMD_INLINE batch<float, A> fms(batch<float, A> const& x, batch<float, A> const& y, batch<float, A> const& z, requires_arch<avx512f>) noexcept
1112
+ {
1113
+ return _mm512_fmsub_ps(x, y, z);
1114
+ }
1115
+
1116
+ template <class A>
1117
+ XSIMD_INLINE batch<double, A> fms(batch<double, A> const& x, batch<double, A> const& y, batch<double, A> const& z, requires_arch<avx512f>) noexcept
1118
+ {
1119
+ return _mm512_fmsub_pd(x, y, z);
1120
+ }
1121
+ // fmas
1122
+ template <class A>
1123
+ XSIMD_INLINE batch<float, A> fmas(batch<float, A> const& x, batch<float, A> const& y, batch<float, A> const& z, requires_arch<avx512f>) noexcept
1124
+ {
1125
+ return _mm512_fmaddsub_ps(x, y, z);
1126
+ }
1127
+
1128
+ template <class A>
1129
+ XSIMD_INLINE batch<double, A> fmas(batch<double, A> const& x, batch<double, A> const& y, batch<double, A> const& z, requires_arch<avx512f>) noexcept
1130
+ {
1131
+ return _mm512_fmaddsub_pd(x, y, z);
1132
+ }
1133
+
1134
+ // from bool
1135
+ template <class A, class T>
1136
+ XSIMD_INLINE batch<T, A> from_bool(batch_bool<T, A> const& self, requires_arch<avx512f>) noexcept
1137
+ {
1138
+ return select(self, batch<T, A>(1), batch<T, A>(0));
1139
+ }
1140
+
1141
+ // from_mask
1142
+ template <class T, class A>
1143
+ XSIMD_INLINE batch_bool<T, A> from_mask(batch_bool<T, A> const&, uint64_t mask, requires_arch<avx512f>) noexcept
1144
+ {
1145
+ return static_cast<typename batch_bool<T, A>::register_type>(mask);
1146
+ }
1147
+
1148
+ // gather
1149
+ template <class T, class A, class U, detail::enable_sized_integral_t<T, 4> = 0, detail::enable_sized_integral_t<U, 4> = 0>
1150
+ XSIMD_INLINE batch<T, A> gather(batch<T, A> const&, T const* src, batch<U, A> const& index,
1151
+ kernel::requires_arch<avx512f>) noexcept
1152
+ {
1153
+ return _mm512_i32gather_epi32(index, static_cast<const void*>(src), sizeof(T));
1154
+ }
1155
+
1156
+ template <class T, class A, class U, detail::enable_sized_integral_t<T, 8> = 0, detail::enable_sized_integral_t<U, 8> = 0>
1157
+ XSIMD_INLINE batch<T, A> gather(batch<T, A> const&, T const* src, batch<U, A> const& index,
1158
+ kernel::requires_arch<avx512f>) noexcept
1159
+ {
1160
+ return _mm512_i64gather_epi64(index, static_cast<const void*>(src), sizeof(T));
1161
+ }
1162
+
1163
+ template <class A, class U, detail::enable_sized_integral_t<U, 4> = 0>
1164
+ XSIMD_INLINE batch<float, A> gather(batch<float, A> const&, float const* src,
1165
+ batch<U, A> const& index,
1166
+ kernel::requires_arch<avx512f>) noexcept
1167
+ {
1168
+ return _mm512_i32gather_ps(index, src, sizeof(float));
1169
+ }
1170
+
1171
+ template <class A, class U, detail::enable_sized_integral_t<U, 8> = 0>
1172
+ XSIMD_INLINE batch<double, A>
1173
+ gather(batch<double, A> const&, double const* src, batch<U, A> const& index,
1174
+ kernel::requires_arch<avx512f>) noexcept
1175
+ {
1176
+ return _mm512_i64gather_pd(index, src, sizeof(double));
1177
+ }
1178
+
1179
+ // gather: handmade conversions
1180
+ template <class A, class V, detail::enable_sized_integral_t<V, 4> = 0>
1181
+ XSIMD_INLINE batch<float, A> gather(batch<float, A> const&, double const* src,
1182
+ batch<V, A> const& index,
1183
+ requires_arch<avx512f>) noexcept
1184
+ {
1185
+ const batch<double, A> low(_mm512_i32gather_pd(_mm512_castsi512_si256(index.data), src, sizeof(double)));
1186
+ const batch<double, A> high(_mm512_i32gather_pd(_mm256_castpd_si256(_mm512_extractf64x4_pd(_mm512_castsi512_pd(index.data), 1)), src, sizeof(double)));
1187
+ return detail::merge_avx(_mm512_cvtpd_ps(low.data), _mm512_cvtpd_ps(high.data));
1188
+ }
1189
+
1190
+ template <class A, class V, detail::enable_sized_integral_t<V, 4> = 0>
1191
+ XSIMD_INLINE batch<int32_t, A> gather(batch<int32_t, A> const&, double const* src,
1192
+ batch<V, A> const& index,
1193
+ requires_arch<avx512f>) noexcept
1194
+ {
1195
+ const batch<double, A> low(_mm512_i32gather_pd(_mm512_castsi512_si256(index.data), src, sizeof(double)));
1196
+ const batch<double, A> high(_mm512_i32gather_pd(_mm256_castpd_si256(_mm512_extractf64x4_pd(_mm512_castsi512_pd(index.data), 1)), src, sizeof(double)));
1197
+ return detail::merge_avx(_mm512_cvtpd_epi32(low.data), _mm512_cvtpd_epi32(high.data));
1198
+ }
1199
+
1200
+ // ge
1201
+ template <class A>
1202
+ XSIMD_INLINE batch_bool<float, A> ge(batch<float, A> const& self, batch<float, A> const& other, requires_arch<avx512f>) noexcept
1203
+ {
1204
+ return _mm512_cmp_ps_mask(self, other, _CMP_GE_OQ);
1205
+ }
1206
+ template <class A>
1207
+ XSIMD_INLINE batch_bool<double, A> ge(batch<double, A> const& self, batch<double, A> const& other, requires_arch<avx512f>) noexcept
1208
+ {
1209
+ return _mm512_cmp_pd_mask(self, other, _CMP_GE_OQ);
1210
+ }
1211
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
1212
+ XSIMD_INLINE batch_bool<T, A> ge(batch<T, A> const& self, batch<T, A> const& other, requires_arch<avx512f>) noexcept
1213
+ {
1214
+ return detail::compare_int_avx512f<A, T, _MM_CMPINT_GE>(self, other);
1215
+ }
1216
+
1217
+ // gt
1218
+ template <class A>
1219
+ XSIMD_INLINE batch_bool<float, A> gt(batch<float, A> const& self, batch<float, A> const& other, requires_arch<avx512f>) noexcept
1220
+ {
1221
+ return _mm512_cmp_ps_mask(self, other, _CMP_GT_OQ);
1222
+ }
1223
+ template <class A>
1224
+ XSIMD_INLINE batch_bool<double, A> gt(batch<double, A> const& self, batch<double, A> const& other, requires_arch<avx512f>) noexcept
1225
+ {
1226
+ return _mm512_cmp_pd_mask(self, other, _CMP_GT_OQ);
1227
+ }
1228
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
1229
+ XSIMD_INLINE batch_bool<T, A> gt(batch<T, A> const& self, batch<T, A> const& other, requires_arch<avx512f>) noexcept
1230
+ {
1231
+ return detail::compare_int_avx512f<A, T, _MM_CMPINT_GT>(self, other);
1232
+ }
1233
+
1234
+ // haddp
1235
+ template <class A>
1236
+ XSIMD_INLINE batch<float, A> haddp(batch<float, A> const* row, requires_arch<avx512f>) noexcept
1237
+ {
1238
+ // The following folds over the vector once:
1239
+ // tmp1 = [a0..8, b0..8]
1240
+ // tmp2 = [a8..f, b8..f]
1241
+ #define XSIMD_AVX512_HADDP_STEP1(I, a, b) \
1242
+ batch<float, avx512f> res##I; \
1243
+ { \
1244
+ auto tmp1 = _mm512_shuffle_f32x4(a, b, _MM_SHUFFLE(1, 0, 1, 0)); \
1245
+ auto tmp2 = _mm512_shuffle_f32x4(a, b, _MM_SHUFFLE(3, 2, 3, 2)); \
1246
+ res##I = _mm512_add_ps(tmp1, tmp2); \
1247
+ }
1248
+
1249
+ XSIMD_AVX512_HADDP_STEP1(0, row[0], row[2]);
1250
+ XSIMD_AVX512_HADDP_STEP1(1, row[4], row[6]);
1251
+ XSIMD_AVX512_HADDP_STEP1(2, row[1], row[3]);
1252
+ XSIMD_AVX512_HADDP_STEP1(3, row[5], row[7]);
1253
+ XSIMD_AVX512_HADDP_STEP1(4, row[8], row[10]);
1254
+ XSIMD_AVX512_HADDP_STEP1(5, row[12], row[14]);
1255
+ XSIMD_AVX512_HADDP_STEP1(6, row[9], row[11]);
1256
+ XSIMD_AVX512_HADDP_STEP1(7, row[13], row[15]);
1257
+
1258
+ #undef XSIMD_AVX512_HADDP_STEP1
1259
+
1260
+ // The following flds the code and shuffles so that hadd_ps produces the correct result
1261
+ // tmp1 = [a0..4, a8..12, b0..4, b8..12] (same for tmp3)
1262
+ // tmp2 = [a5..8, a12..16, b5..8, b12..16] (same for tmp4)
1263
+ // tmp5 = [r1[0], r1[2], r2[0], r2[2], r1[4], r1[6] ...
1264
+ #define XSIMD_AVX512_HADDP_STEP2(I, a, b, c, d) \
1265
+ batch<float, avx2> halfx##I; \
1266
+ { \
1267
+ auto tmp1 = _mm512_shuffle_f32x4(a, b, _MM_SHUFFLE(2, 0, 2, 0)); \
1268
+ auto tmp2 = _mm512_shuffle_f32x4(a, b, _MM_SHUFFLE(3, 1, 3, 1)); \
1269
+ \
1270
+ auto resx1 = _mm512_add_ps(tmp1, tmp2); \
1271
+ \
1272
+ auto tmp3 = _mm512_shuffle_f32x4(c, d, _MM_SHUFFLE(2, 0, 2, 0)); \
1273
+ auto tmp4 = _mm512_shuffle_f32x4(c, d, _MM_SHUFFLE(3, 1, 3, 1)); \
1274
+ \
1275
+ auto resx2 = _mm512_add_ps(tmp3, tmp4); \
1276
+ \
1277
+ auto tmp5 = _mm512_shuffle_ps(resx1, resx2, _MM_SHUFFLE(2, 0, 2, 0)); \
1278
+ auto tmp6 = _mm512_shuffle_ps(resx1, resx2, _MM_SHUFFLE(3, 1, 3, 1)); \
1279
+ \
1280
+ auto resx3 = _mm512_add_ps(tmp5, tmp6); \
1281
+ \
1282
+ halfx##I = _mm256_hadd_ps(_mm256_insertf128_ps(_mm256_castps128_ps256(_mm512_extractf32x4_ps(resx3, 0)), _mm512_extractf32x4_ps(resx3, 1), 1), \
1283
+ _mm256_insertf128_ps(_mm256_castps128_ps256(_mm512_extractf32x4_ps(resx3, 2)), _mm512_extractf32x4_ps(resx3, 3), 1)); \
1284
+ }
1285
+
1286
+ XSIMD_AVX512_HADDP_STEP2(0, res0, res1, res2, res3);
1287
+ XSIMD_AVX512_HADDP_STEP2(1, res4, res5, res6, res7);
1288
+
1289
+ #undef XSIMD_AVX512_HADDP_STEP2
1290
+
1291
+ auto concat = _mm512_castps256_ps512(halfx0);
1292
+ concat = _mm512_castpd_ps(_mm512_insertf64x4(_mm512_castps_pd(concat), _mm256_castps_pd(halfx1), 1));
1293
+ return concat;
1294
+ }
1295
+
1296
+ template <class A>
1297
+ XSIMD_INLINE batch<double, A> haddp(batch<double, A> const* row, requires_arch<avx512f>) noexcept
1298
+ {
1299
+ #define step1(I, a, b) \
1300
+ batch<double, avx512f> res##I; \
1301
+ { \
1302
+ auto tmp1 = _mm512_shuffle_f64x2(a, b, _MM_SHUFFLE(1, 0, 1, 0)); \
1303
+ auto tmp2 = _mm512_shuffle_f64x2(a, b, _MM_SHUFFLE(3, 2, 3, 2)); \
1304
+ res##I = _mm512_add_pd(tmp1, tmp2); \
1305
+ }
1306
+
1307
+ step1(1, row[0], row[2]);
1308
+ step1(2, row[4], row[6]);
1309
+ step1(3, row[1], row[3]);
1310
+ step1(4, row[5], row[7]);
1311
+
1312
+ #undef step1
1313
+
1314
+ auto tmp5 = _mm512_shuffle_f64x2(res1, res2, _MM_SHUFFLE(2, 0, 2, 0));
1315
+ auto tmp6 = _mm512_shuffle_f64x2(res1, res2, _MM_SHUFFLE(3, 1, 3, 1));
1316
+
1317
+ auto resx1 = _mm512_add_pd(tmp5, tmp6);
1318
+
1319
+ auto tmp7 = _mm512_shuffle_f64x2(res3, res4, _MM_SHUFFLE(2, 0, 2, 0));
1320
+ auto tmp8 = _mm512_shuffle_f64x2(res3, res4, _MM_SHUFFLE(3, 1, 3, 1));
1321
+
1322
+ auto resx2 = _mm512_add_pd(tmp7, tmp8);
1323
+
1324
+ auto tmpx = _mm512_shuffle_pd(resx1, resx2, 0b00000000);
1325
+ auto tmpy = _mm512_shuffle_pd(resx1, resx2, 0b11111111);
1326
+
1327
+ return _mm512_add_pd(tmpx, tmpy);
1328
+ }
1329
+
1330
+ // incr_if
1331
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
1332
+ XSIMD_INLINE batch<T, A> incr_if(batch<T, A> const& self, batch_bool<T, A> const& mask, requires_arch<avx512f>) noexcept
1333
+ {
1334
+
1335
+ XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
1336
+ {
1337
+ return _mm512_mask_add_epi32(self, mask.data, self, _mm512_set1_epi32(1));
1338
+ }
1339
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 8)
1340
+ {
1341
+ return _mm512_mask_add_epi64(self, mask.data, self, _mm512_set1_epi64(1));
1342
+ }
1343
+ else
1344
+ {
1345
+ return incr_if(self, mask, common {});
1346
+ }
1347
+ }
1348
+
1349
+ // first (must precede get for two-phase lookup)
1350
+ template <class A>
1351
+ XSIMD_INLINE float first(batch<float, A> const& self, requires_arch<avx512f>) noexcept
1352
+ {
1353
+ return _mm512_cvtss_f32(self);
1354
+ }
1355
+
1356
+ template <class A>
1357
+ XSIMD_INLINE double first(batch<double, A> const& self, requires_arch<avx512f>) noexcept
1358
+ {
1359
+ return _mm512_cvtsd_f64(self);
1360
+ }
1361
+
1362
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
1363
+ XSIMD_INLINE T first(batch<T, A> const& self, requires_arch<avx512f>) noexcept
1364
+ {
1365
+ XSIMD_IF_CONSTEXPR(sizeof(T) == 1)
1366
+ {
1367
+ return static_cast<T>(_mm_cvtsi128_si32(_mm512_castsi512_si128(self)) & 0xFF);
1368
+ }
1369
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 2)
1370
+ {
1371
+ return static_cast<T>(_mm_cvtsi128_si32(_mm512_castsi512_si128(self)) & 0xFFFF);
1372
+ }
1373
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
1374
+ {
1375
+ return static_cast<T>(_mm_cvtsi128_si32(_mm512_castsi512_si128(self)));
1376
+ }
1377
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 8)
1378
+ {
1379
+ batch<T, sse4_2> low = _mm512_castsi512_si128(self);
1380
+ return first(low, sse4_2 {});
1381
+ }
1382
+ else
1383
+ {
1384
+ assert(false && "unsupported arch/op combination");
1385
+ return {};
1386
+ }
1387
+ }
1388
+
1389
+ // get: use valignd/valignq to rotate lane I into position 0 in a single op.
1390
+ template <class A, size_t I>
1391
+ XSIMD_INLINE float get(batch<float, A> const& self, ::xsimd::index<I>, requires_arch<avx512f>) noexcept
1392
+ {
1393
+ XSIMD_IF_CONSTEXPR(I == 0)
1394
+ {
1395
+ return first(self, avx512f {});
1396
+ }
1397
+ const auto rotated = _mm512_alignr_epi32(_mm512_castps_si512(self), _mm512_castps_si512(self), I);
1398
+ return _mm_cvtss_f32(_mm512_castps512_ps128(_mm512_castsi512_ps(rotated)));
1399
+ }
1400
+
1401
+ template <class A, size_t I>
1402
+ XSIMD_INLINE double get(batch<double, A> const& self, ::xsimd::index<I>, requires_arch<avx512f>) noexcept
1403
+ {
1404
+ XSIMD_IF_CONSTEXPR(I == 0)
1405
+ {
1406
+ return first(self, avx512f {});
1407
+ }
1408
+ const auto rotated = _mm512_alignr_epi64(_mm512_castpd_si512(self), _mm512_castpd_si512(self), I);
1409
+ return _mm_cvtsd_f64(_mm512_castpd512_pd128(_mm512_castsi512_pd(rotated)));
1410
+ }
1411
+
1412
+ template <class A, size_t I, class T, class = std::enable_if_t<std::is_integral<T>::value>>
1413
+ XSIMD_INLINE T get(batch<T, A> const& self, ::xsimd::index<I>, requires_arch<avx512f>) noexcept
1414
+ {
1415
+ XSIMD_IF_CONSTEXPR(I == 0)
1416
+ {
1417
+ return first(self, avx512f {});
1418
+ }
1419
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
1420
+ {
1421
+ const auto rotated = _mm512_alignr_epi32(self, self, I);
1422
+ return first(batch<T, sse4_2>(_mm512_castsi512_si128(rotated)), sse4_2 {});
1423
+ }
1424
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 8)
1425
+ {
1426
+ const auto rotated = _mm512_alignr_epi64(self, self, I);
1427
+ return first(batch<T, sse4_2>(_mm512_castsi512_si128(rotated)), sse4_2 {});
1428
+ }
1429
+ else
1430
+ {
1431
+ // 8/16-bit lanes have no sub-dword rotate in AVX-512F; delegate to AVX halves.
1432
+ constexpr size_t elements_per_lane = batch<T, avx>::size;
1433
+ constexpr size_t lane = I / elements_per_lane;
1434
+ constexpr size_t sub_index = I % elements_per_lane;
1435
+ const auto half = (lane == 0) ? detail::lower_half(self) : detail::upper_half(self);
1436
+ return kernel::get(batch<T, avx>(half), ::xsimd::index<sub_index> {}, avx {});
1437
+ }
1438
+ }
1439
+
1440
+ // insert
1441
+ template <class A, size_t I>
1442
+ XSIMD_INLINE batch<float, A> insert(batch<float, A> const& self, float val, index<I>, requires_arch<avx512f>) noexcept
1443
+ {
1444
+
1445
+ int32_t tmp = bit_cast<int32_t>(val);
1446
+ return _mm512_castsi512_ps(_mm512_mask_set1_epi32(_mm512_castps_si512(self), __mmask16(1 << (I & 15)), tmp));
1447
+ }
1448
+
1449
+ template <class A, size_t I>
1450
+ XSIMD_INLINE batch<double, A> insert(batch<double, A> const& self, double val, index<I>, requires_arch<avx512f>) noexcept
1451
+ {
1452
+ int64_t tmp = bit_cast<int64_t>(val);
1453
+ return _mm512_castsi512_pd(_mm512_mask_set1_epi64(_mm512_castpd_si512(self), __mmask8(1 << (I & 7)), tmp));
1454
+ }
1455
+ template <class A, class T, size_t I, class = std::enable_if_t<std::is_integral<T>::value>>
1456
+ XSIMD_INLINE batch<T, A> insert(batch<T, A> const& self, T val, index<I> pos, requires_arch<avx512f>) noexcept
1457
+ {
1458
+ XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
1459
+ {
1460
+ return _mm512_mask_set1_epi32(self, __mmask16(1 << (I & 15)), val);
1461
+ }
1462
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 8)
1463
+ {
1464
+ return _mm512_mask_set1_epi64(self, __mmask8(1 << (I & 7)), val);
1465
+ }
1466
+ else
1467
+ {
1468
+ return insert(self, val, pos, common {});
1469
+ }
1470
+ }
1471
+
1472
+ // isnan
1473
+ template <class A>
1474
+ XSIMD_INLINE batch_bool<float, A> isnan(batch<float, A> const& self, requires_arch<avx512f>) noexcept
1475
+ {
1476
+ return _mm512_cmp_ps_mask(self, self, _CMP_UNORD_Q);
1477
+ }
1478
+ template <class A>
1479
+ XSIMD_INLINE batch_bool<double, A> isnan(batch<double, A> const& self, requires_arch<avx512f>) noexcept
1480
+ {
1481
+ return _mm512_cmp_pd_mask(self, self, _CMP_UNORD_Q);
1482
+ }
1483
+
1484
+ // ldexp
1485
+ template <class A>
1486
+ XSIMD_INLINE batch<float, A> ldexp(const batch<float, A>& self, const batch<as_integer_t<float>, A>& other, requires_arch<avx512f>) noexcept
1487
+ {
1488
+ return _mm512_scalef_ps(self, _mm512_cvtepi32_ps(other));
1489
+ }
1490
+
1491
+ template <class A>
1492
+ XSIMD_INLINE batch<double, A> ldexp(const batch<double, A>& self, const batch<as_integer_t<double>, A>& other, requires_arch<avx512f>) noexcept
1493
+ {
1494
+ // FIXME: potential data loss here when converting other elements to
1495
+ // int32 before converting them back to double.
1496
+ __m512d adjusted_index = _mm512_cvtepi32_pd(_mm512_cvtepi64_epi32(other));
1497
+ return _mm512_scalef_pd(self, adjusted_index);
1498
+ }
1499
+
1500
+ // le
1501
+ template <class A>
1502
+ XSIMD_INLINE batch_bool<float, A> le(batch<float, A> const& self, batch<float, A> const& other, requires_arch<avx512f>) noexcept
1503
+ {
1504
+ return _mm512_cmp_ps_mask(self, other, _CMP_LE_OQ);
1505
+ }
1506
+ template <class A>
1507
+ XSIMD_INLINE batch_bool<double, A> le(batch<double, A> const& self, batch<double, A> const& other, requires_arch<avx512f>) noexcept
1508
+ {
1509
+ return _mm512_cmp_pd_mask(self, other, _CMP_LE_OQ);
1510
+ }
1511
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
1512
+ XSIMD_INLINE batch_bool<T, A> le(batch<T, A> const& self, batch<T, A> const& other, requires_arch<avx512f>) noexcept
1513
+ {
1514
+ return detail::compare_int_avx512f<A, T, _MM_CMPINT_LE>(self, other);
1515
+ }
1516
+
1517
+ namespace detail
1518
+ {
1519
+ // Adapted from https://github.com/serge-sans-paille/fast-bitset-from-bool-array
1520
+ // Generate a bitset from an array of boolean.
1521
+ XSIMD_INLINE unsigned char tobitset(unsigned char unpacked[8])
1522
+ {
1523
+ uint64_t data;
1524
+ memcpy(&data, unpacked, sizeof(uint64_t));
1525
+
1526
+ const uint64_t magic = (0x80 + 0x4000 + 0x200000 + 0x10000000 + 0x0800000000 + 0x040000000000 + 0x02000000000000 + 0x0100000000000000);
1527
+
1528
+ unsigned char res = ((data * magic) >> 56) & 0xFF;
1529
+ return res;
1530
+ }
1531
+ }
1532
+
1533
+ // load mask
1534
+ template <class A, class T>
1535
+ XSIMD_INLINE batch_bool<T, A> load_unaligned(bool const* mem, batch_bool<T, A>, requires_arch<avx512f>) noexcept
1536
+ {
1537
+ using register_type = typename batch_bool<T, A>::register_type;
1538
+ constexpr auto size = batch_bool<T, A>::size;
1539
+ constexpr auto iter = size / 8;
1540
+ static_assert((size % 8) == 0, "incorrect size of bool batch");
1541
+ register_type mask = 0;
1542
+ for (std::size_t i = 0; i < iter; ++i)
1543
+ {
1544
+ unsigned char block = detail::tobitset((unsigned char*)mem + i * 8);
1545
+ mask |= (register_type(block) << (i * 8));
1546
+ }
1547
+ return mask;
1548
+ }
1549
+
1550
+ // load_aligned
1551
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
1552
+ XSIMD_INLINE batch<T, A> load_aligned(T const* mem, convert<T>, requires_arch<avx512f>) noexcept
1553
+ {
1554
+ return _mm512_load_si512((__m512i const*)mem);
1555
+ }
1556
+ template <class A>
1557
+ XSIMD_INLINE batch<float, A> load_aligned(float const* mem, convert<float>, requires_arch<avx512f>) noexcept
1558
+ {
1559
+ return _mm512_load_ps(mem);
1560
+ }
1561
+ template <class A>
1562
+ XSIMD_INLINE batch<double, A> load_aligned(double const* mem, convert<double>, requires_arch<avx512f>) noexcept
1563
+ {
1564
+ return _mm512_load_pd(mem);
1565
+ }
1566
+
1567
+ // load_complex
1568
+ namespace detail
1569
+ {
1570
+ template <class A>
1571
+ XSIMD_INLINE batch<std::complex<float>, A> load_complex(batch<float, A> const& hi, batch<float, A> const& lo, requires_arch<avx512f>) noexcept
1572
+ {
1573
+ __m512i real_idx = _mm512_setr_epi32(0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30);
1574
+ __m512i imag_idx = _mm512_setr_epi32(1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31);
1575
+ auto real = _mm512_permutex2var_ps(hi, real_idx, lo);
1576
+ auto imag = _mm512_permutex2var_ps(hi, imag_idx, lo);
1577
+ return { real, imag };
1578
+ }
1579
+ template <class A>
1580
+ XSIMD_INLINE batch<std::complex<double>, A> load_complex(batch<double, A> const& hi, batch<double, A> const& lo, requires_arch<avx512f>) noexcept
1581
+ {
1582
+ __m512i real_idx = _mm512_setr_epi64(0, 2, 4, 6, 8, 10, 12, 14);
1583
+ __m512i imag_idx = _mm512_setr_epi64(1, 3, 5, 7, 9, 11, 13, 15);
1584
+ auto real = _mm512_permutex2var_pd(hi, real_idx, lo);
1585
+ auto imag = _mm512_permutex2var_pd(hi, imag_idx, lo);
1586
+ return { real, imag };
1587
+ }
1588
+ }
1589
+
1590
+ // load_unaligned
1591
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
1592
+ XSIMD_INLINE batch<T, A> load_unaligned(T const* mem, convert<T>, requires_arch<avx512f>) noexcept
1593
+ {
1594
+ return _mm512_loadu_si512((__m512i const*)mem);
1595
+ }
1596
+ template <class A>
1597
+ XSIMD_INLINE batch<float, A> load_unaligned(float const* mem, convert<float>, requires_arch<avx512f>) noexcept
1598
+ {
1599
+ return _mm512_loadu_ps(mem);
1600
+ }
1601
+ template <class A>
1602
+ XSIMD_INLINE batch<double, A> load_unaligned(double const* mem, convert<double>, requires_arch<avx512f>) noexcept
1603
+ {
1604
+ return _mm512_loadu_pd(mem);
1605
+ }
1606
+
1607
+ // load_stream
1608
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value, void>>
1609
+ XSIMD_INLINE batch<T, A> load_stream(T const* mem, convert<T>, requires_arch<avx512f>) noexcept
1610
+ {
1611
+ return _mm512_stream_load_si512((__m512i*)mem);
1612
+ }
1613
+ template <class A>
1614
+ XSIMD_INLINE batch<float, A> load_stream(float const* mem, convert<float>, requires_arch<avx512f>) noexcept
1615
+ {
1616
+ return _mm512_castsi512_ps(_mm512_stream_load_si512((__m512i*)mem));
1617
+ }
1618
+ template <class A>
1619
+ XSIMD_INLINE batch<double, A> load_stream(double const* mem, convert<double>, requires_arch<avx512f>) noexcept
1620
+ {
1621
+ return _mm512_castsi512_pd(_mm512_stream_load_si512((__m512i*)mem));
1622
+ }
1623
+
1624
+ // lt
1625
+ template <class A>
1626
+ XSIMD_INLINE batch_bool<float, A> lt(batch<float, A> const& self, batch<float, A> const& other, requires_arch<avx512f>) noexcept
1627
+ {
1628
+ return _mm512_cmp_ps_mask(self, other, _CMP_LT_OQ);
1629
+ }
1630
+ template <class A>
1631
+ XSIMD_INLINE batch_bool<double, A> lt(batch<double, A> const& self, batch<double, A> const& other, requires_arch<avx512f>) noexcept
1632
+ {
1633
+ return _mm512_cmp_pd_mask(self, other, _CMP_LT_OQ);
1634
+ }
1635
+
1636
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
1637
+ XSIMD_INLINE batch_bool<T, A> lt(batch<T, A> const& self, batch<T, A> const& other, requires_arch<avx512f>) noexcept
1638
+ {
1639
+ return detail::compare_int_avx512f<A, T, _MM_CMPINT_LT>(self, other);
1640
+ }
1641
+
1642
+ // mask
1643
+ template <class A, class T>
1644
+ XSIMD_INLINE uint64_t mask(batch_bool<T, A> const& self, requires_arch<avx512f>) noexcept
1645
+ {
1646
+ return self.data;
1647
+ }
1648
+
1649
+ // max
1650
+ template <class A>
1651
+ XSIMD_INLINE batch<float, A> max(batch<float, A> const& self, batch<float, A> const& other, requires_arch<avx512f>) noexcept
1652
+ {
1653
+ return _mm512_max_ps(other, self);
1654
+ }
1655
+ template <class A>
1656
+ XSIMD_INLINE batch<double, A> max(batch<double, A> const& self, batch<double, A> const& other, requires_arch<avx512f>) noexcept
1657
+ {
1658
+ return _mm512_max_pd(other, self);
1659
+ }
1660
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
1661
+ XSIMD_INLINE batch<T, A> max(batch<T, A> const& self, batch<T, A> const& other, requires_arch<avx512f>) noexcept
1662
+ {
1663
+ if (std::is_signed<T>::value)
1664
+ {
1665
+ XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
1666
+ {
1667
+ return _mm512_max_epi32(self, other);
1668
+ }
1669
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 8)
1670
+ {
1671
+ return _mm512_max_epi64(self, other);
1672
+ }
1673
+ else
1674
+ {
1675
+ return detail::fwd_to_avx([](__m256i s, __m256i o) noexcept
1676
+ { return max(batch<T, avx2>(s), batch<T, avx2>(o)); },
1677
+ self, other);
1678
+ }
1679
+ }
1680
+ else
1681
+ {
1682
+ XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
1683
+ {
1684
+ return _mm512_max_epu32(self, other);
1685
+ }
1686
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 8)
1687
+ {
1688
+ return _mm512_max_epu64(self, other);
1689
+ }
1690
+ else
1691
+ {
1692
+ return detail::fwd_to_avx([](__m256i s, __m256i o) noexcept
1693
+ { return max(batch<T, avx2>(s), batch<T, avx2>(o)); },
1694
+ self, other);
1695
+ }
1696
+ }
1697
+ }
1698
+
1699
+ // min
1700
+ template <class A>
1701
+ XSIMD_INLINE batch<float, A> min(batch<float, A> const& self, batch<float, A> const& other, requires_arch<avx512f>) noexcept
1702
+ {
1703
+ return _mm512_min_ps(other, self);
1704
+ }
1705
+ template <class A>
1706
+ XSIMD_INLINE batch<double, A> min(batch<double, A> const& self, batch<double, A> const& other, requires_arch<avx512f>) noexcept
1707
+ {
1708
+ return _mm512_min_pd(other, self);
1709
+ }
1710
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
1711
+ XSIMD_INLINE batch<T, A> min(batch<T, A> const& self, batch<T, A> const& other, requires_arch<avx512f>) noexcept
1712
+ {
1713
+ if (std::is_signed<T>::value)
1714
+ {
1715
+ XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
1716
+ {
1717
+ return _mm512_min_epi32(self, other);
1718
+ }
1719
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 8)
1720
+ {
1721
+ return _mm512_min_epi64(self, other);
1722
+ }
1723
+ else
1724
+ {
1725
+ return detail::fwd_to_avx([](__m256i s, __m256i o) noexcept
1726
+ { return min(batch<T, avx2>(s), batch<T, avx2>(o)); },
1727
+ self, other);
1728
+ }
1729
+ }
1730
+ else
1731
+ {
1732
+ XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
1733
+ {
1734
+ return _mm512_min_epu32(self, other);
1735
+ }
1736
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 8)
1737
+ {
1738
+ return _mm512_min_epu64(self, other);
1739
+ }
1740
+ else
1741
+ {
1742
+ return detail::fwd_to_avx([](__m256i s, __m256i o) noexcept
1743
+ { return min(batch<T, avx2>(s), batch<T, avx2>(o)); },
1744
+ self, other);
1745
+ }
1746
+ }
1747
+ }
1748
+
1749
+ // mul
1750
+ template <class A>
1751
+ XSIMD_INLINE batch<float, A> mul(batch<float, A> const& self, batch<float, A> const& other, requires_arch<avx512f>) noexcept
1752
+ {
1753
+ return _mm512_mul_ps(self, other);
1754
+ }
1755
+ template <class A>
1756
+ XSIMD_INLINE batch<double, A> mul(batch<double, A> const& self, batch<double, A> const& other, requires_arch<avx512f>) noexcept
1757
+ {
1758
+ return _mm512_mul_pd(self, other);
1759
+ }
1760
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
1761
+ XSIMD_INLINE batch<T, A> mul(batch<T, A> const& self, batch<T, A> const& other, requires_arch<avx512f>) noexcept
1762
+ {
1763
+ XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
1764
+ {
1765
+ return _mm512_mullo_epi32(self, other);
1766
+ }
1767
+ else
1768
+ {
1769
+ return detail::fwd_to_avx([](__m256i s, __m256i o) noexcept
1770
+ { return mul(batch<T, avx2>(s), batch<T, avx2>(o)); },
1771
+ self, other);
1772
+ }
1773
+ }
1774
+
1775
+ // nearbyint
1776
+ template <class A>
1777
+ XSIMD_INLINE batch<float, A> nearbyint(batch<float, A> const& self, requires_arch<avx512f>) noexcept
1778
+ {
1779
+ return _mm512_roundscale_round_ps(self, _MM_FROUND_TO_NEAREST_INT, _MM_FROUND_CUR_DIRECTION);
1780
+ }
1781
+ template <class A>
1782
+ XSIMD_INLINE batch<double, A> nearbyint(batch<double, A> const& self, requires_arch<avx512f>) noexcept
1783
+ {
1784
+ return _mm512_roundscale_round_pd(self, _MM_FROUND_TO_NEAREST_INT, _MM_FROUND_CUR_DIRECTION);
1785
+ }
1786
+
1787
+ // nearbyint_as_int
1788
+ template <class A>
1789
+ XSIMD_INLINE batch<int32_t, A> nearbyint_as_int(batch<float, A> const& self,
1790
+ requires_arch<avx512f>) noexcept
1791
+ {
1792
+ return _mm512_cvtps_epi32(self);
1793
+ }
1794
+
1795
+ // neg
1796
+ template <class A, class T>
1797
+ XSIMD_INLINE batch<T, A> neg(batch<T, A> const& self, requires_arch<avx512f>) noexcept
1798
+ {
1799
+ return 0 - self;
1800
+ }
1801
+
1802
+ // neq
1803
+ template <class A>
1804
+ XSIMD_INLINE batch_bool<float, A> neq(batch<float, A> const& self, batch<float, A> const& other, requires_arch<avx512f>) noexcept
1805
+ {
1806
+ return _mm512_cmp_ps_mask(self, other, _CMP_NEQ_UQ);
1807
+ }
1808
+ template <class A>
1809
+ XSIMD_INLINE batch_bool<double, A> neq(batch<double, A> const& self, batch<double, A> const& other, requires_arch<avx512f>) noexcept
1810
+ {
1811
+ return _mm512_cmp_pd_mask(self, other, _CMP_NEQ_UQ);
1812
+ }
1813
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
1814
+ XSIMD_INLINE batch_bool<T, A> neq(batch<T, A> const& self, batch<T, A> const& other, requires_arch<avx512f>) noexcept
1815
+ {
1816
+ return ~(self == other);
1817
+ }
1818
+
1819
+ template <class A, class T>
1820
+ XSIMD_INLINE batch_bool<T, A> neq(batch_bool<T, A> const& self, batch_bool<T, A> const& other, requires_arch<avx512f>) noexcept
1821
+ {
1822
+ using register_type = typename batch_bool<T, A>::register_type;
1823
+ return register_type(self.data ^ other.data);
1824
+ }
1825
+
1826
+ // reciprocal
1827
+ template <class A>
1828
+ XSIMD_INLINE batch<float, A>
1829
+ reciprocal(batch<float, A> const& self,
1830
+ kernel::requires_arch<avx512f>) noexcept
1831
+ {
1832
+ return _mm512_rcp14_ps(self);
1833
+ }
1834
+
1835
+ template <class A>
1836
+ XSIMD_INLINE batch<double, A>
1837
+ reciprocal(batch<double, A> const& self,
1838
+ kernel::requires_arch<avx512f>) noexcept
1839
+ {
1840
+ return _mm512_rcp14_pd(self);
1841
+ }
1842
+
1843
+ // reduce_add
1844
+ template <class A>
1845
+ XSIMD_INLINE float reduce_add(batch<float, A> const& rhs, requires_arch<avx512f>) noexcept
1846
+ {
1847
+ return _mm512_reduce_add_ps(rhs);
1848
+ }
1849
+ template <class A>
1850
+ XSIMD_INLINE double reduce_add(batch<double, A> const& rhs, requires_arch<avx512f>) noexcept
1851
+ {
1852
+ return _mm512_reduce_add_pd(rhs);
1853
+ }
1854
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
1855
+ XSIMD_INLINE T reduce_add(batch<T, A> const& self, requires_arch<avx512f>) noexcept
1856
+ {
1857
+ __m256i low = detail::lower_half(self), high = detail::upper_half(self);
1858
+ batch<T, avx2> blow(low), bhigh(high);
1859
+ return reduce_add(blow, avx2 {}) + reduce_add(bhigh, avx2 {});
1860
+ }
1861
+
1862
+ // reduce_max
1863
+ template <class A, class T, class = std::enable_if_t<(sizeof(T) == 1)>>
1864
+ XSIMD_INLINE T reduce_max(batch<T, A> const& self, requires_arch<avx512f>) noexcept
1865
+ {
1866
+ constexpr batch_constant<uint64_t, A, 5, 6, 7, 8, 0, 0, 0, 0> mask;
1867
+ batch<T, A> step = _mm512_permutexvar_epi64(mask.as_batch(), self);
1868
+ batch<T, A> acc = max(self, step);
1869
+ __m256i low = _mm512_castsi512_si256(acc);
1870
+ return reduce_max(batch<T, avx2>(low));
1871
+ }
1872
+
1873
+ // reduce_min
1874
+ template <class A, class T, class = std::enable_if_t<(sizeof(T) == 1)>>
1875
+ XSIMD_INLINE T reduce_min(batch<T, A> const& self, requires_arch<avx512f>) noexcept
1876
+ {
1877
+ constexpr batch_constant<uint64_t, A, 5, 6, 7, 8, 0, 0, 0, 0> mask;
1878
+ batch<T, A> step = _mm512_permutexvar_epi64(mask.as_batch(), self);
1879
+ batch<T, A> acc = min(self, step);
1880
+ __m256i low = _mm512_castsi512_si256(acc);
1881
+ return reduce_min(batch<T, avx2>(low));
1882
+ }
1883
+
1884
+ // reduce_mul
1885
+ template <class A>
1886
+ XSIMD_INLINE float reduce_mul(batch<float, A> const& rhs, requires_arch<avx512f>) noexcept
1887
+ {
1888
+ return _mm512_reduce_mul_ps(rhs);
1889
+ }
1890
+ template <class A>
1891
+ XSIMD_INLINE double reduce_mul(batch<double, A> const& rhs, requires_arch<avx512f>) noexcept
1892
+ {
1893
+ return _mm512_reduce_mul_pd(rhs);
1894
+ }
1895
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
1896
+ XSIMD_INLINE T reduce_mul(batch<T, A> const& self, requires_arch<avx512f>) noexcept
1897
+ {
1898
+ XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
1899
+ {
1900
+ return _mm512_reduce_mul_epi32(self);
1901
+ }
1902
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 8)
1903
+ {
1904
+ return _mm512_reduce_mul_epi64(self);
1905
+ }
1906
+ else
1907
+ {
1908
+ __m256i low = detail::lower_half(self), high = detail::upper_half(self);
1909
+ batch<T, avx2> blow(low), bhigh(high);
1910
+ return reduce_mul(blow, avx2 {}) * reduce_mul(bhigh, avx2 {});
1911
+ }
1912
+ }
1913
+
1914
+ // rsqrt
1915
+ template <class A>
1916
+ XSIMD_INLINE batch<float, A> rsqrt(batch<float, A> const& val, requires_arch<avx512f>) noexcept
1917
+ {
1918
+ return _mm512_rsqrt14_ps(val);
1919
+ }
1920
+ template <class A>
1921
+ XSIMD_INLINE batch<double, A> rsqrt(batch<double, A> const& val, requires_arch<avx512f>) noexcept
1922
+ {
1923
+ return _mm512_rsqrt14_pd(val);
1924
+ }
1925
+
1926
+ // sadd
1927
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
1928
+ XSIMD_INLINE batch<T, A> sadd(batch<T, A> const& self, batch<T, A> const& other, requires_arch<avx512f>) noexcept
1929
+ {
1930
+ if (std::is_signed<T>::value)
1931
+ {
1932
+ auto mask = other < 0;
1933
+ auto self_pos_branch = min(std::numeric_limits<T>::max() - other, self);
1934
+ auto self_neg_branch = max(std::numeric_limits<T>::min() - other, self);
1935
+ return other + select(mask, self_neg_branch, self_pos_branch);
1936
+ }
1937
+ else
1938
+ {
1939
+ const auto diffmax = std::numeric_limits<T>::max() - self;
1940
+ const auto mindiff = min(diffmax, other);
1941
+ return self + mindiff;
1942
+ }
1943
+ }
1944
+
1945
+ // scatter
1946
+ template <class A, class T,
1947
+ class = std::enable_if_t<std::is_same<uint32_t, T>::value || std::is_same<int32_t, T>::value>>
1948
+ XSIMD_INLINE void scatter(batch<T, A> const& src, T* dst,
1949
+ batch<int32_t, A> const& index,
1950
+ kernel::requires_arch<avx512f>) noexcept
1951
+ {
1952
+ _mm512_i32scatter_epi32(dst, index, src, sizeof(T));
1953
+ }
1954
+
1955
+ template <class A, class T,
1956
+ class = std::enable_if_t<std::is_same<uint64_t, T>::value || std::is_same<int64_t, T>::value>>
1957
+ XSIMD_INLINE void scatter(batch<T, A> const& src, T* dst,
1958
+ batch<int64_t, A> const& index,
1959
+ kernel::requires_arch<avx512f>) noexcept
1960
+ {
1961
+ _mm512_i64scatter_epi64(dst, index, src, sizeof(T));
1962
+ }
1963
+
1964
+ template <class A>
1965
+ XSIMD_INLINE void scatter(batch<float, A> const& src, float* dst,
1966
+ batch<int32_t, A> const& index,
1967
+ kernel::requires_arch<avx512f>) noexcept
1968
+ {
1969
+ _mm512_i32scatter_ps(dst, index, src, sizeof(float));
1970
+ }
1971
+
1972
+ template <class A>
1973
+ XSIMD_INLINE void scatter(batch<double, A> const& src, double* dst,
1974
+ batch<int64_t, A> const& index,
1975
+ kernel::requires_arch<avx512f>) noexcept
1976
+ {
1977
+ _mm512_i64scatter_pd(dst, index, src, sizeof(double));
1978
+ }
1979
+
1980
+ // select
1981
+ template <class A>
1982
+ XSIMD_INLINE batch<float, A> select(batch_bool<float, A> const& cond, batch<float, A> const& true_br, batch<float, A> const& false_br, requires_arch<avx512f>) noexcept
1983
+ {
1984
+ return _mm512_mask_blend_ps(cond, false_br, true_br);
1985
+ }
1986
+ template <class A>
1987
+ XSIMD_INLINE batch<double, A> select(batch_bool<double, A> const& cond, batch<double, A> const& true_br, batch<double, A> const& false_br, requires_arch<avx512f>) noexcept
1988
+ {
1989
+ return _mm512_mask_blend_pd(cond, false_br, true_br);
1990
+ }
1991
+
1992
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
1993
+ XSIMD_INLINE batch<T, A> select(batch_bool<T, A> const& cond, batch<T, A> const& true_br, batch<T, A> const& false_br, requires_arch<avx512f>) noexcept
1994
+ {
1995
+ XSIMD_IF_CONSTEXPR(sizeof(T) == 1)
1996
+ {
1997
+ alignas(avx2::alignment()) uint8_t buffer[64];
1998
+ // FIXME: ultra inefficient
1999
+ for (int i = 0; i < 64; ++i)
2000
+ buffer[i] = cond.data & (1ull << i) ? 0xFF : 0;
2001
+ __m256i cond_low = batch<uint8_t, avx2>::load_aligned(&buffer[0]);
2002
+ __m256i cond_hi = batch<uint8_t, avx2>::load_aligned(&buffer[32]);
2003
+
2004
+ __m256i true_low = detail::lower_half(true_br), true_hi = detail::upper_half(true_br);
2005
+ __m256i false_low = detail::lower_half(false_br), false_hi = detail::upper_half(false_br);
2006
+
2007
+ __m256i res_low = select(batch_bool<T, avx2>(cond_low), batch<T, avx2>(true_low), batch<T, avx2>(false_low), avx2 {});
2008
+ __m256i res_hi = select(batch_bool<T, avx2>(cond_hi), batch<T, avx2>(true_hi), batch<T, avx2>(false_hi), avx2 {});
2009
+ return detail::merge_avx(res_low, res_hi);
2010
+ }
2011
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 2)
2012
+ {
2013
+ __m256i cond_low = _mm512_maskz_cvtepi32_epi16((uint64_t)cond.data & 0xFFFF, _mm512_set1_epi32(~0));
2014
+ __m256i cond_hi = _mm512_maskz_cvtepi32_epi16((uint64_t)cond.data >> 16, _mm512_set1_epi32(~0));
2015
+
2016
+ __m256i true_low = detail::lower_half(true_br), true_hi = detail::upper_half(true_br);
2017
+ __m256i false_low = detail::lower_half(false_br), false_hi = detail::upper_half(false_br);
2018
+
2019
+ __m256i res_low = select(batch_bool<T, avx2>(cond_low), batch<T, avx2>(true_low), batch<T, avx2>(false_low), avx2 {});
2020
+ __m256i res_hi = select(batch_bool<T, avx2>(cond_hi), batch<T, avx2>(true_hi), batch<T, avx2>(false_hi), avx2 {});
2021
+ return detail::merge_avx(res_low, res_hi);
2022
+ }
2023
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
2024
+ {
2025
+ return _mm512_mask_blend_epi32(cond, false_br, true_br);
2026
+ }
2027
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 8)
2028
+ {
2029
+ return _mm512_mask_blend_epi64(cond, false_br, true_br);
2030
+ }
2031
+ else
2032
+ {
2033
+ assert(false && "unsupported arch/type combination");
2034
+ return {};
2035
+ }
2036
+ }
2037
+
2038
+ template <class A, class T, bool... Values, class = std::enable_if_t<std::is_integral<T>::value>>
2039
+ XSIMD_INLINE batch<T, A> select(batch_bool_constant<T, A, Values...> const&, batch<T, A> const& true_br, batch<T, A> const& false_br, requires_arch<avx512f>) noexcept
2040
+ {
2041
+ return select(batch_bool<T, A> { Values... }, true_br, false_br, avx512f {});
2042
+ }
2043
+
2044
+ namespace detail
2045
+ {
2046
+ template <class T>
2047
+ using enable_signed_integer_t = std::enable_if_t<std::is_integral<T>::value && std::is_signed<T>::value,
2048
+ int>;
2049
+
2050
+ template <class T>
2051
+ using enable_unsigned_integer_t = std::enable_if_t<std::is_integral<T>::value && std::is_unsigned<T>::value,
2052
+ int>;
2053
+ }
2054
+
2055
+ // set
2056
+ template <class A>
2057
+ XSIMD_INLINE batch<float, A> set(batch<float, A> const&, requires_arch<avx512f>, float v0, float v1, float v2, float v3, float v4, float v5, float v6, float v7, float v8, float v9, float v10, float v11, float v12, float v13, float v14, float v15) noexcept
2058
+ {
2059
+ return _mm512_setr_ps(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15);
2060
+ }
2061
+
2062
+ template <class A>
2063
+ XSIMD_INLINE batch<double, A> set(batch<double, A> const&, requires_arch<avx512f>, double v0, double v1, double v2, double v3, double v4, double v5, double v6, double v7) noexcept
2064
+ {
2065
+ return _mm512_setr_pd(v0, v1, v2, v3, v4, v5, v6, v7);
2066
+ }
2067
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
2068
+ XSIMD_INLINE batch<T, A> set(batch<T, A> const&, requires_arch<avx512f>, T v0, T v1, T v2, T v3, T v4, T v5, T v6, T v7) noexcept
2069
+ {
2070
+ return _mm512_set_epi64(v7, v6, v5, v4, v3, v2, v1, v0);
2071
+ }
2072
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
2073
+ XSIMD_INLINE batch<T, A> set(batch<T, A> const&, requires_arch<avx512f>, T v0, T v1, T v2, T v3, T v4, T v5, T v6, T v7,
2074
+ T v8, T v9, T v10, T v11, T v12, T v13, T v14, T v15) noexcept
2075
+ {
2076
+ return _mm512_setr_epi32(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15);
2077
+ }
2078
+ template <class A, class T, detail::enable_signed_integer_t<T> = 0>
2079
+ XSIMD_INLINE batch<T, A> set(batch<T, A> const&, requires_arch<avx512f>, T v0, T v1, T v2, T v3, T v4, T v5, T v6, T v7,
2080
+ T v8, T v9, T v10, T v11, T v12, T v13, T v14, T v15,
2081
+ T v16, T v17, T v18, T v19, T v20, T v21, T v22, T v23,
2082
+ T v24, T v25, T v26, T v27, T v28, T v29, T v30, T v31) noexcept
2083
+ {
2084
+ #if defined(__clang__) || __GNUC__
2085
+ return __extension__(__m512i)(__v32hi) {
2086
+ v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15,
2087
+ v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31
2088
+ };
2089
+ #else
2090
+ return _mm512_set_epi16(v31, v30, v29, v28, v27, v26, v25, v24, v23, v22, v21, v20, v19, v18, v17, v16,
2091
+ v15, v14, v13, v12, v11, v10, v9, v8, v7, v6, v5, v4, v3, v2, v1, v0);
2092
+ #endif
2093
+ }
2094
+
2095
+ template <class A, class T, detail::enable_unsigned_integer_t<T> = 0>
2096
+ XSIMD_INLINE batch<T, A> set(batch<T, A> const&, requires_arch<avx512f>, T v0, T v1, T v2, T v3, T v4, T v5, T v6, T v7,
2097
+ T v8, T v9, T v10, T v11, T v12, T v13, T v14, T v15,
2098
+ T v16, T v17, T v18, T v19, T v20, T v21, T v22, T v23,
2099
+ T v24, T v25, T v26, T v27, T v28, T v29, T v30, T v31) noexcept
2100
+ {
2101
+ #if defined(__clang__) || __GNUC__
2102
+ return __extension__(__m512i)(__v32hu) {
2103
+ v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15,
2104
+ v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31
2105
+ };
2106
+ #else
2107
+ return _mm512_set_epi16(v31, v30, v29, v28, v27, v26, v25, v24, v23, v22, v21, v20, v19, v18, v17, v16,
2108
+ v15, v14, v13, v12, v11, v10, v9, v8, v7, v6, v5, v4, v3, v2, v1, v0);
2109
+ #endif
2110
+ }
2111
+
2112
+ template <class A, class T, detail::enable_signed_integer_t<T> = 0>
2113
+ XSIMD_INLINE batch<T, A> set(batch<T, A> const&, requires_arch<avx512f>, T v0, T v1, T v2, T v3, T v4, T v5, T v6, T v7,
2114
+ T v8, T v9, T v10, T v11, T v12, T v13, T v14, T v15,
2115
+ T v16, T v17, T v18, T v19, T v20, T v21, T v22, T v23,
2116
+ T v24, T v25, T v26, T v27, T v28, T v29, T v30, T v31,
2117
+ T v32, T v33, T v34, T v35, T v36, T v37, T v38, T v39,
2118
+ T v40, T v41, T v42, T v43, T v44, T v45, T v46, T v47,
2119
+ T v48, T v49, T v50, T v51, T v52, T v53, T v54, T v55,
2120
+ T v56, T v57, T v58, T v59, T v60, T v61, T v62, T v63) noexcept
2121
+ {
2122
+
2123
+ #if defined(__clang__) || __GNUC__
2124
+ return __extension__(__m512i)(__v64qi) {
2125
+ v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15,
2126
+ v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31,
2127
+ v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47,
2128
+ v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62, v63
2129
+ };
2130
+ #else
2131
+ return _mm512_set_epi8(v63, v62, v61, v60, v59, v58, v57, v56, v55, v54, v53, v52, v51, v50, v49, v48,
2132
+ v47, v46, v45, v44, v43, v42, v41, v40, v39, v38, v37, v36, v35, v34, v33, v32,
2133
+ v31, v30, v29, v28, v27, v26, v25, v24, v23, v22, v21, v20, v19, v18, v17, v16,
2134
+ v15, v14, v13, v12, v11, v10, v9, v8, v7, v6, v5, v4, v3, v2, v1, v0);
2135
+ #endif
2136
+ }
2137
+ template <class A, class T, detail::enable_unsigned_integer_t<T> = 0>
2138
+ XSIMD_INLINE batch<T, A> set(batch<T, A> const&, requires_arch<avx512f>, T v0, T v1, T v2, T v3, T v4, T v5, T v6, T v7,
2139
+ T v8, T v9, T v10, T v11, T v12, T v13, T v14, T v15,
2140
+ T v16, T v17, T v18, T v19, T v20, T v21, T v22, T v23,
2141
+ T v24, T v25, T v26, T v27, T v28, T v29, T v30, T v31,
2142
+ T v32, T v33, T v34, T v35, T v36, T v37, T v38, T v39,
2143
+ T v40, T v41, T v42, T v43, T v44, T v45, T v46, T v47,
2144
+ T v48, T v49, T v50, T v51, T v52, T v53, T v54, T v55,
2145
+ T v56, T v57, T v58, T v59, T v60, T v61, T v62, T v63) noexcept
2146
+ {
2147
+
2148
+ #if defined(__clang__) || __GNUC__
2149
+ return __extension__(__m512i)(__v64qu) {
2150
+ v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15,
2151
+ v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31,
2152
+ v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47,
2153
+ v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62, v63
2154
+ };
2155
+ #else
2156
+ return _mm512_set_epi8(v63, v62, v61, v60, v59, v58, v57, v56, v55, v54, v53, v52, v51, v50, v49, v48,
2157
+ v47, v46, v45, v44, v43, v42, v41, v40, v39, v38, v37, v36, v35, v34, v33, v32,
2158
+ v31, v30, v29, v28, v27, v26, v25, v24, v23, v22, v21, v20, v19, v18, v17, v16,
2159
+ v15, v14, v13, v12, v11, v10, v9, v8, v7, v6, v5, v4, v3, v2, v1, v0);
2160
+ #endif
2161
+ }
2162
+
2163
+ template <class A, class T, class... Values>
2164
+ XSIMD_INLINE batch_bool<T, A> set(batch_bool<T, A> const&, requires_arch<avx512f>, Values... values) noexcept
2165
+ {
2166
+ static_assert(sizeof...(Values) == batch_bool<T, A>::size, "consistent init");
2167
+ using register_type = typename batch_bool<T, A>::register_type;
2168
+ register_type r = 0;
2169
+ unsigned shift = 0;
2170
+ (void)std::initializer_list<register_type> { (r |= register_type(values ? 1 : 0) << (shift++))... };
2171
+ return r;
2172
+ }
2173
+
2174
+ // shuffle
2175
+ template <class A, class ITy, ITy I0, ITy I1, ITy I2, ITy I3, ITy I4, ITy I5, ITy I6, ITy I7, ITy I8, ITy I9, ITy I10, ITy I11, ITy I12, ITy I13, ITy I14, ITy I15>
2176
+ XSIMD_INLINE batch<float, A> shuffle(batch<float, A> const& x, batch<float, A> const& y,
2177
+ batch_constant<ITy, A, I0, I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15> mask,
2178
+ requires_arch<avx512f>) noexcept
2179
+ {
2180
+ constexpr uint32_t smask = (I0 & 0x3) | ((I1 & 0x3) << 2) | ((I2 & 0x3) << 4) | ((I3 & 0x3) << 6);
2181
+
2182
+ // shuffle within lane
2183
+ if ((I4 == I0 + 4) && (I5 == I1 + 4) && (I6 == I2 + 4) && (I7 == I3 + 4) && (I8 == I0 + 8) && (I9 == I1 + 8) && (I10 == I2 + 8) && (I11 == I3 + 8) && (I12 == I0 + 12) && (I13 == I1 + 12) && (I14 == I2 + 12) && (I15 == I3 + 12) && I0 < 4 && I1 < 4 && I2 >= 16 && I2 < 20 && I3 >= 16 && I3 < 20)
2184
+ return _mm512_shuffle_ps(x, y, smask);
2185
+
2186
+ // shuffle within opposite lane
2187
+ if ((I4 == I0 + 4) && (I5 == I1 + 4) && (I6 == I2 + 4) && (I7 == I3 + 4) && (I8 == I0 + 8) && (I9 == I1 + 8) && (I10 == I2 + 8) && (I11 == I3 + 8) && (I12 == I0 + 12) && (I13 == I1 + 12) && (I14 == I2 + 12) && (I15 == I3 + 12) && I2 < 4 && I3 < 4 && I0 >= 16 && I0 < 20 && I1 >= 16 && I1 < 20)
2188
+ return _mm512_shuffle_ps(y, x, smask);
2189
+
2190
+ return shuffle(x, y, mask, common {});
2191
+ }
2192
+
2193
+ template <class A, class ITy, ITy I0, ITy I1, ITy I2, ITy I3, ITy I4, ITy I5, ITy I6, ITy I7>
2194
+ XSIMD_INLINE batch<double, A> shuffle(batch<double, A> const& x, batch<double, A> const& y, batch_constant<ITy, A, I0, I1, I2, I3, I4, I5, I6, I7> mask, requires_arch<avx512f>) noexcept
2195
+ {
2196
+ constexpr uint32_t smask = (I0 & 0x1) | ((I1 & 0x1) << 1) | ((I2 & 0x1) << 2) | ((I3 & 0x1) << 3) | ((I4 & 0x1) << 4) | ((I5 & 0x1) << 5) | ((I6 & 0x1) << 6) | ((I7 & 0x1) << 7);
2197
+ // shuffle within lane
2198
+ if (I0 < 2 && I1 >= 8 && I1 < 10 && I2 >= 2 && I2 < 4 && I3 >= 10 && I3 < 12 && I4 >= 4 && I4 < 6 && I5 >= 12 && I5 < 14 && I6 >= 6 && I6 < 8 && I7 >= 14)
2199
+ return _mm512_shuffle_pd(x, y, smask);
2200
+
2201
+ // shuffle within opposite lane
2202
+ if (I1 < 2 && I0 >= 8 && I0 < 10 && I3 >= 2 && I3 < 4 && I2 >= 10 && I2 < 12 && I5 >= 4 && I5 < 6 && I4 >= 12 && I4 < 14 && I7 >= 6 && I7 < 8 && I6 >= 14)
2203
+ return _mm512_shuffle_pd(y, x, smask);
2204
+
2205
+ return shuffle(x, y, mask, common {});
2206
+ }
2207
+
2208
+ // slide_left
2209
+ namespace detail
2210
+ {
2211
+ template <size_t N>
2212
+ struct make_slide_left_pattern
2213
+ {
2214
+ static constexpr size_t get(size_t i, size_t)
2215
+ {
2216
+ return i >= N ? i - N : 0;
2217
+ }
2218
+ };
2219
+
2220
+ template <size_t N, class A, class T>
2221
+ XSIMD_INLINE batch<T, A> slide_left_aligned_u32(batch<T, A> const& x, requires_arch<avx512f>) noexcept
2222
+ {
2223
+ static_assert((N & 3) == 0 || N >= 64, "N must be aligned to 32 bits");
2224
+
2225
+ if (N == 0)
2226
+ {
2227
+ return x;
2228
+ }
2229
+ if (N >= 64)
2230
+ {
2231
+ return batch<T, A>(T(0));
2232
+ }
2233
+
2234
+ __mmask16 mask = uint16_t(0xFFFFu << (N / 4));
2235
+
2236
+ if ((N & 15) == 0)
2237
+ {
2238
+ const uint8_t imm8 = uint8_t(0xe4 << (2 * (N / 16)));
2239
+ return _mm512_maskz_shuffle_i32x4(mask, x, x, imm8);
2240
+ }
2241
+
2242
+ auto slide_pattern = make_batch_constant<uint32_t, detail::make_slide_left_pattern<N / 4>, A>();
2243
+ return _mm512_maskz_permutexvar_epi32(mask, slide_pattern.as_batch(), x);
2244
+ }
2245
+ }
2246
+
2247
+ template <size_t N, class A, class T>
2248
+ XSIMD_INLINE batch<T, A> slide_left(batch<T, A> const& x, requires_arch<avx512f>) noexcept
2249
+ {
2250
+ constexpr size_t NN = N & ~3;
2251
+ if (N == NN || NN >= 64)
2252
+ {
2253
+ // Call fast path
2254
+ return detail::slide_left_aligned_u32<NN>(x, A {});
2255
+ }
2256
+
2257
+ __m512i xl = detail::slide_left_aligned_u32<NN, A, T>(_mm512_slli_epi32(x, 8 * (N - NN)), A {});
2258
+ __m512i xr = detail::slide_left_aligned_u32<NN + 4, A, T>(_mm512_srli_epi32(x, 32 - 8 * (N - NN)), A {});
2259
+ return _mm512_or_epi32(xl, xr);
2260
+ }
2261
+
2262
+ // slide_right
2263
+ namespace detail
2264
+ {
2265
+ template <size_t N>
2266
+ struct make_slide_right_pattern
2267
+ {
2268
+ static constexpr size_t get(size_t i, size_t n)
2269
+ {
2270
+ return i < (n - N) ? i + N : 0;
2271
+ }
2272
+ };
2273
+
2274
+ template <size_t N, class A, class T>
2275
+ XSIMD_INLINE batch<T, A> slide_right_aligned_u32(batch<T, A> const& x, requires_arch<avx512f>) noexcept
2276
+ {
2277
+ static_assert((N & 3) == 0 || N >= 64, "N must be aligned to 32 bits");
2278
+
2279
+ if (N == 0)
2280
+ {
2281
+ return x;
2282
+ }
2283
+ if (N >= 64)
2284
+ {
2285
+ return batch<T, A>(T(0));
2286
+ }
2287
+
2288
+ __mmask16 mask = 0xFFFFu >> (N / 4);
2289
+
2290
+ if ((N & 15) == 0)
2291
+ {
2292
+ const uint8_t imm8 = 0xe4 >> (2 * (N / 16));
2293
+ return _mm512_maskz_shuffle_i32x4(mask, x, x, imm8);
2294
+ }
2295
+
2296
+ auto slide_pattern = make_batch_constant<uint32_t, detail::make_slide_right_pattern<N / 4>, A>();
2297
+ return _mm512_maskz_permutexvar_epi32(mask, slide_pattern.as_batch(), x);
2298
+ }
2299
+ }
2300
+ template <size_t N, class A, class T>
2301
+ XSIMD_INLINE batch<T, A> slide_right(batch<T, A> const& x, requires_arch<avx512f>) noexcept
2302
+ {
2303
+ constexpr size_t NN = N & ~3;
2304
+ if (N == NN || NN >= 64)
2305
+ {
2306
+ // Call fast path
2307
+ return detail::slide_right_aligned_u32<NN>(x, A {});
2308
+ }
2309
+
2310
+ __m512i xl = detail::slide_right_aligned_u32<NN + 4, A, T>(_mm512_slli_epi32(x, 32 - 8 * (N - NN)), A {});
2311
+ __m512i xr = detail::slide_right_aligned_u32<NN, A, T>(_mm512_srli_epi32(x, 8 * (N - NN)), A {});
2312
+ return _mm512_or_epi32(xl, xr);
2313
+ }
2314
+
2315
+ // sqrt
2316
+ template <class A>
2317
+ XSIMD_INLINE batch<float, A> sqrt(batch<float, A> const& val, requires_arch<avx512f>) noexcept
2318
+ {
2319
+ return _mm512_sqrt_ps(val);
2320
+ }
2321
+ template <class A>
2322
+ XSIMD_INLINE batch<double, A> sqrt(batch<double, A> const& val, requires_arch<avx512f>) noexcept
2323
+ {
2324
+ return _mm512_sqrt_pd(val);
2325
+ }
2326
+
2327
+ // ssub
2328
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
2329
+ XSIMD_INLINE batch<T, A> ssub(batch<T, A> const& self, batch<T, A> const& other, requires_arch<avx512f>) noexcept
2330
+ {
2331
+ if (std::is_signed<T>::value)
2332
+ {
2333
+ return sadd(self, -other);
2334
+ }
2335
+ else
2336
+ {
2337
+ const auto diff = min(self, other);
2338
+ return self - diff;
2339
+ }
2340
+ }
2341
+
2342
+ // store
2343
+ template <class T, class A>
2344
+ XSIMD_INLINE void store(batch_bool<T, A> const& self, bool* mem, requires_arch<avx512f>) noexcept
2345
+ {
2346
+ using register_type = typename batch_bool<T, A>::register_type;
2347
+ constexpr auto size = batch_bool<T, A>::size;
2348
+ for (std::size_t i = 0; i < size; ++i)
2349
+ mem[i] = self.data & (register_type(1) << i);
2350
+ }
2351
+
2352
+ // store_aligned
2353
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
2354
+ XSIMD_INLINE void store_aligned(T* mem, batch<T, A> const& self, requires_arch<avx512f>) noexcept
2355
+ {
2356
+ return _mm512_store_si512((__m512i*)mem, self);
2357
+ }
2358
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
2359
+ XSIMD_INLINE void store_aligned(T* mem, batch_bool<T, A> const& self, requires_arch<avx512f>) noexcept
2360
+ {
2361
+ return _mm512_store_si512((__m512i*)mem, self);
2362
+ }
2363
+ template <class A>
2364
+ XSIMD_INLINE void store_aligned(float* mem, batch<float, A> const& self, requires_arch<avx512f>) noexcept
2365
+ {
2366
+ return _mm512_store_ps(mem, self);
2367
+ }
2368
+ template <class A>
2369
+ XSIMD_INLINE void store_aligned(double* mem, batch<double, A> const& self, requires_arch<avx512f>) noexcept
2370
+ {
2371
+ return _mm512_store_pd(mem, self);
2372
+ }
2373
+
2374
+ // store_unaligned
2375
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
2376
+ XSIMD_INLINE void store_unaligned(T* mem, batch<T, A> const& self, requires_arch<avx512f>) noexcept
2377
+ {
2378
+ return _mm512_storeu_si512((__m512i*)mem, self);
2379
+ }
2380
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
2381
+ XSIMD_INLINE void store_unaligned(T* mem, batch_bool<T, A> const& self, requires_arch<avx512f>) noexcept
2382
+ {
2383
+ return _mm512_storeu_si512((__m512i*)mem, self);
2384
+ }
2385
+ template <class A>
2386
+ XSIMD_INLINE void store_unaligned(float* mem, batch<float, A> const& self, requires_arch<avx512f>) noexcept
2387
+ {
2388
+ return _mm512_storeu_ps(mem, self);
2389
+ }
2390
+ template <class A>
2391
+ XSIMD_INLINE void store_unaligned(double* mem, batch<double, A> const& self, requires_arch<avx512f>) noexcept
2392
+ {
2393
+ return _mm512_storeu_pd(mem, self);
2394
+ }
2395
+
2396
+ // store_stream
2397
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value, void>>
2398
+ XSIMD_INLINE void store_stream(T* mem, batch<T, A> const& self, requires_arch<avx512f>) noexcept
2399
+ {
2400
+ _mm512_stream_si512((__m512i*)mem, self);
2401
+ }
2402
+ template <class A>
2403
+ XSIMD_INLINE void store_stream(float* mem, batch<float, A> const& self, requires_arch<avx512f>) noexcept
2404
+ {
2405
+ _mm512_stream_ps(mem, self);
2406
+ }
2407
+ template <class A>
2408
+ XSIMD_INLINE void store_stream(double* mem, batch<double, A> const& self, requires_arch<avx512f>) noexcept
2409
+ {
2410
+ _mm512_stream_pd(mem, self);
2411
+ }
2412
+
2413
+ // sub
2414
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
2415
+ XSIMD_INLINE batch<T, A> sub(batch<T, A> const& self, batch<T, A> const& other, requires_arch<avx512f>) noexcept
2416
+ {
2417
+ XSIMD_IF_CONSTEXPR(sizeof(T) == 1)
2418
+ {
2419
+ return detail::fwd_to_avx([](__m256i s, __m256i o) noexcept
2420
+ { return sub(batch<T, avx2>(s), batch<T, avx2>(o)); },
2421
+ self, other);
2422
+ }
2423
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 2)
2424
+ {
2425
+ return detail::fwd_to_avx([](__m256i s, __m256i o) noexcept
2426
+ { return sub(batch<T, avx2>(s), batch<T, avx2>(o)); },
2427
+ self, other);
2428
+ }
2429
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
2430
+ {
2431
+ return _mm512_sub_epi32(self, other);
2432
+ }
2433
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 8)
2434
+ {
2435
+ return _mm512_sub_epi64(self, other);
2436
+ }
2437
+ else
2438
+ {
2439
+ assert(false && "unsupported arch/op combination");
2440
+ return {};
2441
+ }
2442
+ }
2443
+ template <class A>
2444
+ XSIMD_INLINE batch<float, A> sub(batch<float, A> const& self, batch<float, A> const& other, requires_arch<avx512f>) noexcept
2445
+ {
2446
+ return _mm512_sub_ps(self, other);
2447
+ }
2448
+ template <class A>
2449
+ XSIMD_INLINE batch<double, A> sub(batch<double, A> const& self, batch<double, A> const& other, requires_arch<avx512f>) noexcept
2450
+ {
2451
+ return _mm512_sub_pd(self, other);
2452
+ }
2453
+
2454
+ // swizzle (dynamic version)
2455
+ template <class A>
2456
+ XSIMD_INLINE batch<float, A> swizzle(batch<float, A> const& self, batch<uint32_t, A> mask, requires_arch<avx512f>) noexcept
2457
+ {
2458
+ return _mm512_permutexvar_ps(mask, self);
2459
+ }
2460
+
2461
+ template <class A>
2462
+ XSIMD_INLINE batch<double, A> swizzle(batch<double, A> const& self, batch<uint64_t, A> mask, requires_arch<avx512f>) noexcept
2463
+ {
2464
+ return _mm512_permutexvar_pd(mask, self);
2465
+ }
2466
+
2467
+ template <class A>
2468
+ XSIMD_INLINE batch<uint64_t, A> swizzle(batch<uint64_t, A> const& self, batch<uint64_t, A> mask, requires_arch<avx512f>) noexcept
2469
+ {
2470
+ return _mm512_permutexvar_epi64(mask, self);
2471
+ }
2472
+
2473
+ template <class A>
2474
+ XSIMD_INLINE batch<int64_t, A> swizzle(batch<int64_t, A> const& self, batch<uint64_t, A> mask, requires_arch<avx512f>) noexcept
2475
+ {
2476
+ return bitwise_cast<int64_t>(swizzle(bitwise_cast<uint64_t>(self), mask, avx512f {}));
2477
+ }
2478
+
2479
+ template <class A>
2480
+ XSIMD_INLINE batch<uint32_t, A> swizzle(batch<uint32_t, A> const& self, batch<uint32_t, A> mask, requires_arch<avx512f>) noexcept
2481
+ {
2482
+ return _mm512_permutexvar_epi32(mask, self);
2483
+ }
2484
+
2485
+ template <class A>
2486
+ XSIMD_INLINE batch<int32_t, A> swizzle(batch<int32_t, A> const& self, batch<uint32_t, A> mask, requires_arch<avx512f>) noexcept
2487
+ {
2488
+ return bitwise_cast<int32_t>(swizzle(bitwise_cast<uint32_t>(self), mask, avx512f {}));
2489
+ }
2490
+
2491
+ template <class A, uint32_t V0, uint32_t V1, uint32_t V2, uint32_t V3, uint32_t V4, uint32_t V5, uint32_t V6, uint32_t V7,
2492
+ uint32_t V8, uint32_t V9, uint32_t V10, uint32_t V11, uint32_t V12, uint32_t V13, uint32_t V14, uint32_t V15>
2493
+ XSIMD_INLINE batch<float, A> swizzle(batch<float, A> const& self,
2494
+ batch_constant<uint32_t, A, V0, V1, V2, V3, V4, V5, V6, V7, V8, V9, V10, V11, V12, V13, V14, V15> mask,
2495
+ requires_arch<avx512f>) noexcept
2496
+ {
2497
+ XSIMD_IF_CONSTEXPR(detail::is_identity(mask))
2498
+ {
2499
+ return self;
2500
+ }
2501
+ XSIMD_IF_CONSTEXPR(!detail::is_cross_lane(mask))
2502
+ {
2503
+ constexpr int imm0 = detail::mod_shuffle(V0, V1, V2, V3);
2504
+ constexpr int imm1 = detail::mod_shuffle(V4, V5, V6, V7);
2505
+ constexpr int imm2 = detail::mod_shuffle(V8, V9, V10, V11);
2506
+ constexpr int imm3 = detail::mod_shuffle(V12, V13, V14, V15);
2507
+ XSIMD_IF_CONSTEXPR(imm0 == imm1 && imm0 == imm2 && imm0 == imm3)
2508
+ {
2509
+ return _mm512_permute_ps(self, imm0);
2510
+ }
2511
+ }
2512
+ return swizzle(self, mask.as_batch(), avx512f {});
2513
+ }
2514
+ template <class A, uint64_t V0, uint64_t V1, uint64_t V2, uint64_t V3, uint64_t V4, uint64_t V5, uint64_t V6, uint64_t V7>
2515
+ XSIMD_INLINE batch<double, A> swizzle(batch<double, A> const& self,
2516
+ batch_constant<uint64_t, A, V0, V1, V2, V3, V4, V5, V6, V7> mask,
2517
+ requires_arch<avx512f>) noexcept
2518
+ {
2519
+ XSIMD_IF_CONSTEXPR(detail::is_identity(mask))
2520
+ {
2521
+ return self;
2522
+ }
2523
+ XSIMD_IF_CONSTEXPR(!detail::is_cross_lane(mask))
2524
+ {
2525
+ constexpr auto imm = ((V0 & 1) << 0) | ((V1 & 1) << 1) | ((V2 & 1) << 2) | ((V3 & 1) << 3) | ((V4 & 1) << 4) | ((V5 & 1) << 5) | ((V6 & 1) << 6) | ((V7 & 1) << 7);
2526
+ return _mm512_permute_pd(self, imm);
2527
+ }
2528
+ constexpr bool dup_lo = detail::is_dup_lo(mask);
2529
+ constexpr bool dup_hi = detail::is_dup_hi(mask);
2530
+ XSIMD_IF_CONSTEXPR(dup_lo || dup_hi)
2531
+ {
2532
+ const batch<double, avx2> half = _mm512_extractf64x4_pd(self, dup_lo ? 0 : 1);
2533
+ constexpr std::conditional_t<dup_lo, batch_constant<uint64_t, avx2, V0 % 4, V1 % 4, V2 % 4, V3 % 4>,
2534
+ batch_constant<uint64_t, avx2, V4 % 4, V5 % 4, V6 % 4, V7 % 4>>
2535
+ half_mask {};
2536
+ return _mm512_broadcast_f64x4(swizzle(half, half_mask, avx2 {}));
2537
+ }
2538
+ // General case
2539
+ return swizzle(self, mask.as_batch(), avx512f {});
2540
+ }
2541
+
2542
+ template <class A, uint64_t... Vs>
2543
+ XSIMD_INLINE batch<uint64_t, A> swizzle(batch<uint64_t, A> const& self, batch_constant<uint64_t, A, Vs...> mask, requires_arch<avx512f>) noexcept
2544
+ {
2545
+ return swizzle(self, mask.as_batch(), avx512f {});
2546
+ }
2547
+
2548
+ template <class A, uint64_t... Vs>
2549
+ XSIMD_INLINE batch<int64_t, A> swizzle(batch<int64_t, A> const& self, batch_constant<uint64_t, A, Vs...> mask, requires_arch<avx512f>) noexcept
2550
+ {
2551
+ return swizzle(self, mask.as_batch(), avx512f {});
2552
+ }
2553
+
2554
+ template <class A, uint32_t... Vs>
2555
+ XSIMD_INLINE batch<uint32_t, A> swizzle(batch<uint32_t, A> const& self, batch_constant<uint32_t, A, Vs...> mask, requires_arch<avx512f>) noexcept
2556
+ {
2557
+ return swizzle(self, mask.as_batch(), avx512f {});
2558
+ }
2559
+
2560
+ template <class A, uint32_t... Vs>
2561
+ XSIMD_INLINE batch<int32_t, A> swizzle(batch<int32_t, A> const& self, batch_constant<uint32_t, A, Vs...> mask, requires_arch<avx512f>) noexcept
2562
+ {
2563
+ return swizzle(self, mask.as_batch(), avx512f {});
2564
+ }
2565
+
2566
+ namespace detail
2567
+ {
2568
+ template <class T, class A, T... Idx>
2569
+ struct is_pair_of_contiguous_indices;
2570
+
2571
+ template <class T, class A>
2572
+ struct is_pair_of_contiguous_indices<T, A> : std::true_type
2573
+ {
2574
+ };
2575
+
2576
+ template <class T, class A, T Idx0, T Idx1, T... Idx>
2577
+ struct is_pair_of_contiguous_indices<T, A, Idx0, Idx1, Idx...> : std::conditional_t<(Idx0 % 2 == 0) && (Idx0 + 1 == Idx1), is_pair_of_contiguous_indices<T, A, Idx...>, std::false_type>
2578
+ {
2579
+ };
2580
+
2581
+ template <class A, uint16_t I0, uint16_t I1, uint16_t I2, uint16_t I3, uint16_t I4, uint16_t I5, uint16_t I6, uint16_t I7,
2582
+ uint16_t I8, uint16_t I9, uint16_t I10, uint16_t I11, uint16_t I12, uint16_t I13, uint16_t I14, uint16_t I15,
2583
+ uint16_t I16, uint16_t I17, uint16_t I18, uint16_t I19, uint16_t I20, uint16_t I21, uint16_t I22, uint16_t I23,
2584
+ uint16_t I24, uint16_t I25, uint16_t I26, uint16_t I27, uint16_t I28, uint16_t I29, uint16_t I30, uint16_t I31>
2585
+ struct fold_batch_constant
2586
+ {
2587
+ using type = batch_constant<uint32_t, A, I0 / 2, I2 / 2, I4 / 2, I6 / 2, I8 / 2, I10 / 2, I12 / 2, I14 / 2,
2588
+ I16 / 2, I18 / 2, I20 / 2, I22 / 2, I24 / 2, I26 / 2, I28 / 2, I30 / 2>;
2589
+ };
2590
+
2591
+ template <class A, uint16_t... Is>
2592
+ constexpr bool is_reduce_pattern()
2593
+ {
2594
+ // The actual pattern is {1, 1, 0, 1, 0, 1, ..., 0, 1}
2595
+ if (sizeof...(Is) != batch<uint16_t, A>::size)
2596
+ return false;
2597
+ uint16_t pattern[] = { Is... };
2598
+ if (pattern[0] != 1)
2599
+ return false;
2600
+ for (size_t i = 1; i < sizeof...(Is); i += 1)
2601
+ {
2602
+ if (pattern[i] != (i & 1))
2603
+ return false;
2604
+ }
2605
+ return true;
2606
+ }
2607
+ }
2608
+
2609
+ template <class A, uint16_t... Idx>
2610
+ XSIMD_INLINE batch<uint16_t, A> swizzle(batch<uint16_t, A> const& self, batch_constant<uint16_t, A, Idx...> mask, requires_arch<avx512f>) noexcept
2611
+ {
2612
+ XSIMD_IF_CONSTEXPR(detail::is_pair_of_contiguous_indices<uint16_t, A, Idx...>::value)
2613
+ {
2614
+ constexpr typename detail::fold_batch_constant<A, Idx...>::type mask32;
2615
+ return _mm512_permutexvar_epi32(static_cast<batch<uint32_t, A>>(mask32), self);
2616
+ }
2617
+ else XSIMD_IF_CONSTEXPR(detail::is_reduce_pattern<A, Idx...>())
2618
+ {
2619
+ // FIXME: this sequence is very inefficient, but it's here to catch
2620
+ // a pattern generated by detail::reduce from xsimd_common_math.hpp.
2621
+ // The whole pattern is actually decently folded by GCC and Clang,
2622
+ // so bare with it.
2623
+ constexpr batch_constant<uint32_t, A, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0> mask32;
2624
+ auto tmp = _mm512_permutexvar_epi32(static_cast<batch<uint32_t, A>>(mask32), self);
2625
+
2626
+ alignas(A::alignment()) uint16_t buffer[32];
2627
+ _mm512_store_si512((__m512i*)&buffer[0], tmp);
2628
+ buffer[0] = buffer[1];
2629
+ return _mm512_load_si512(&buffer[0]);
2630
+ }
2631
+ else
2632
+ {
2633
+ return swizzle(self, mask, common {});
2634
+ }
2635
+ }
2636
+
2637
+ template <class A, uint16_t... Vs>
2638
+ XSIMD_INLINE batch<int16_t, A>
2639
+ swizzle(batch<int16_t, A> const& self, batch_constant<uint16_t, A, Vs...> mask, requires_arch<avx512f>) noexcept
2640
+ {
2641
+ return bitwise_cast<int16_t>(swizzle(bitwise_cast<uint16_t>(self), mask, avx512f {}));
2642
+ }
2643
+
2644
+ // transpose
2645
+ template <class A>
2646
+ XSIMD_INLINE void transpose(batch<uint16_t, A>* matrix_begin, batch<uint16_t, A>* matrix_end, requires_arch<avx512f>) noexcept
2647
+ {
2648
+ assert((matrix_end - matrix_begin == batch<uint16_t, A>::size) && "correctly sized matrix");
2649
+ (void)matrix_end;
2650
+ batch<uint16_t, avx2> tmp_lo0[16];
2651
+ for (int i = 0; i < 16; ++i)
2652
+ tmp_lo0[i] = _mm512_castsi512_si256(matrix_begin[i]);
2653
+ transpose(tmp_lo0 + 0, tmp_lo0 + 16, avx2 {});
2654
+
2655
+ batch<uint16_t, avx2> tmp_hi0[16];
2656
+ for (int i = 0; i < 16; ++i)
2657
+ tmp_hi0[i] = _mm512_castsi512_si256(matrix_begin[16 + i]);
2658
+ transpose(tmp_hi0 + 0, tmp_hi0 + 16, avx2 {});
2659
+
2660
+ batch<uint16_t, avx2> tmp_lo1[16];
2661
+ for (int i = 0; i < 16; ++i)
2662
+ tmp_lo1[i] = _mm512_extracti64x4_epi64(matrix_begin[i], 1);
2663
+ transpose(tmp_lo1 + 0, tmp_lo1 + 16, avx2 {});
2664
+
2665
+ batch<uint16_t, avx2> tmp_hi1[16];
2666
+ for (int i = 0; i < 16; ++i)
2667
+ tmp_hi1[i] = _mm512_extracti64x4_epi64(matrix_begin[16 + i], 1);
2668
+ transpose(tmp_hi1 + 0, tmp_hi1 + 16, avx2 {});
2669
+
2670
+ for (int i = 0; i < 16; ++i)
2671
+ matrix_begin[i] = detail::merge_avx(tmp_lo0[i], tmp_hi0[i]);
2672
+ for (int i = 0; i < 16; ++i)
2673
+ matrix_begin[i + 16] = detail::merge_avx(tmp_lo1[i], tmp_hi1[i]);
2674
+ }
2675
+ template <class A>
2676
+ XSIMD_INLINE void transpose(batch<int16_t, A>* matrix_begin, batch<int16_t, A>* matrix_end, requires_arch<avx512f>) noexcept
2677
+ {
2678
+ return transpose(reinterpret_cast<batch<uint16_t, A>*>(matrix_begin), reinterpret_cast<batch<uint16_t, A>*>(matrix_end), A {});
2679
+ }
2680
+
2681
+ template <class A>
2682
+ XSIMD_INLINE void transpose(batch<uint8_t, A>* matrix_begin, batch<uint8_t, A>* matrix_end, requires_arch<avx512f>) noexcept
2683
+ {
2684
+ assert((matrix_end - matrix_begin == batch<uint8_t, A>::size) && "correctly sized matrix");
2685
+ (void)matrix_end;
2686
+ batch<uint8_t, avx2> tmp_lo0[32];
2687
+ for (int i = 0; i < 32; ++i)
2688
+ tmp_lo0[i] = _mm512_castsi512_si256(matrix_begin[i]);
2689
+ transpose(tmp_lo0 + 0, tmp_lo0 + 32, avx2 {});
2690
+
2691
+ batch<uint8_t, avx2> tmp_hi0[32];
2692
+ for (int i = 0; i < 32; ++i)
2693
+ tmp_hi0[i] = _mm512_castsi512_si256(matrix_begin[32 + i]);
2694
+ transpose(tmp_hi0 + 0, tmp_hi0 + 32, avx2 {});
2695
+
2696
+ batch<uint8_t, avx2> tmp_lo1[32];
2697
+ for (int i = 0; i < 32; ++i)
2698
+ tmp_lo1[i] = _mm512_extracti64x4_epi64(matrix_begin[i], 1);
2699
+ transpose(tmp_lo1 + 0, tmp_lo1 + 32, avx2 {});
2700
+
2701
+ batch<uint8_t, avx2> tmp_hi1[32];
2702
+ for (int i = 0; i < 32; ++i)
2703
+ tmp_hi1[i] = _mm512_extracti64x4_epi64(matrix_begin[32 + i], 1);
2704
+ transpose(tmp_hi1 + 0, tmp_hi1 + 32, avx2 {});
2705
+
2706
+ for (int i = 0; i < 32; ++i)
2707
+ matrix_begin[i] = detail::merge_avx(tmp_lo0[i], tmp_hi0[i]);
2708
+ for (int i = 0; i < 32; ++i)
2709
+ matrix_begin[i + 32] = detail::merge_avx(tmp_lo1[i], tmp_hi1[i]);
2710
+ }
2711
+ template <class A>
2712
+ XSIMD_INLINE void transpose(batch<int8_t, A>* matrix_begin, batch<int8_t, A>* matrix_end, requires_arch<avx512f>) noexcept
2713
+ {
2714
+ return transpose(reinterpret_cast<batch<uint8_t, A>*>(matrix_begin), reinterpret_cast<batch<uint8_t, A>*>(matrix_end), A {});
2715
+ }
2716
+
2717
+ // trunc
2718
+ template <class A>
2719
+ XSIMD_INLINE batch<float, A>
2720
+ trunc(batch<float, A> const& self, requires_arch<avx512f>) noexcept
2721
+ {
2722
+ return _mm512_roundscale_round_ps(self, _MM_FROUND_TO_ZERO, _MM_FROUND_CUR_DIRECTION);
2723
+ }
2724
+ template <class A>
2725
+ XSIMD_INLINE batch<double, A>
2726
+ trunc(batch<double, A> const& self, requires_arch<avx512f>) noexcept
2727
+ {
2728
+ return _mm512_roundscale_round_pd(self, _MM_FROUND_TO_ZERO, _MM_FROUND_CUR_DIRECTION);
2729
+ }
2730
+
2731
+ // zip_hi
2732
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
2733
+ XSIMD_INLINE batch<T, A>
2734
+ zip_hi(batch<T, A> const& self, batch<T, A> const& other, requires_arch<avx512f>) noexcept
2735
+ {
2736
+ __m512i lo, hi;
2737
+ XSIMD_IF_CONSTEXPR(sizeof(T) == 1)
2738
+ {
2739
+ assert(false && "not implemented yet");
2740
+ return {};
2741
+ }
2742
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 2)
2743
+ {
2744
+ assert(false && "not implemented yet");
2745
+ return {};
2746
+ }
2747
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
2748
+ {
2749
+ lo = _mm512_unpacklo_epi32(self, other);
2750
+ hi = _mm512_unpackhi_epi32(self, other);
2751
+ }
2752
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 8)
2753
+ {
2754
+ lo = _mm512_unpacklo_epi64(self, other);
2755
+ hi = _mm512_unpackhi_epi64(self, other);
2756
+ }
2757
+ else
2758
+ {
2759
+ assert(false && "unsupported arch/op combination");
2760
+ return {};
2761
+ }
2762
+ return _mm512_inserti32x4(
2763
+ _mm512_inserti32x4(
2764
+ _mm512_inserti32x4(hi, _mm512_extracti32x4_epi32(lo, 2), 0),
2765
+ _mm512_extracti32x4_epi32(lo, 3),
2766
+ 2),
2767
+ _mm512_extracti32x4_epi32(hi, 2),
2768
+ 1);
2769
+ }
2770
+ template <class A>
2771
+ XSIMD_INLINE batch<float, A>
2772
+ zip_hi(batch<float, A> const& self, batch<float, A> const& other, requires_arch<avx512f>) noexcept
2773
+ {
2774
+ auto lo = _mm512_unpacklo_ps(self, other);
2775
+ auto hi = _mm512_unpackhi_ps(self, other);
2776
+ return _mm512_insertf32x4(
2777
+ _mm512_insertf32x4(
2778
+ _mm512_insertf32x4(hi, _mm512_extractf32x4_ps(lo, 2), 0),
2779
+ _mm512_extractf32x4_ps(lo, 3),
2780
+ 2),
2781
+ _mm512_extractf32x4_ps(hi, 2),
2782
+ 1);
2783
+ }
2784
+ template <class A>
2785
+ XSIMD_INLINE batch<double, A>
2786
+ zip_hi(batch<double, A> const& self, batch<double, A> const& other, requires_arch<avx512f>) noexcept
2787
+ {
2788
+ auto lo = _mm512_castpd_ps(_mm512_unpacklo_pd(self, other));
2789
+ auto hi = _mm512_castpd_ps(_mm512_unpackhi_pd(self, other));
2790
+ return _mm512_castps_pd(_mm512_insertf32x4(
2791
+ _mm512_insertf32x4(
2792
+ _mm512_insertf32x4(hi, _mm512_extractf32x4_ps(lo, 2), 0),
2793
+ _mm512_extractf32x4_ps(lo, 3),
2794
+ 2),
2795
+ _mm512_extractf32x4_ps(hi, 2),
2796
+ 1));
2797
+ }
2798
+
2799
+ // zip_lo
2800
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
2801
+ XSIMD_INLINE batch<T, A>
2802
+ zip_lo(batch<T, A> const& self, batch<T, A> const& other, requires_arch<avx512f>) noexcept
2803
+ {
2804
+ __m512i lo, hi;
2805
+ XSIMD_IF_CONSTEXPR(sizeof(T) == 1)
2806
+ {
2807
+ assert(false && "not implemented yet");
2808
+ return {};
2809
+ }
2810
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 2)
2811
+ {
2812
+ assert(false && "not implemented yet");
2813
+ return {};
2814
+ }
2815
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
2816
+ {
2817
+ lo = _mm512_unpacklo_epi32(self, other);
2818
+ hi = _mm512_unpackhi_epi32(self, other);
2819
+ }
2820
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 8)
2821
+ {
2822
+ lo = _mm512_unpacklo_epi64(self, other);
2823
+ hi = _mm512_unpackhi_epi64(self, other);
2824
+ }
2825
+ else
2826
+ {
2827
+ assert(false && "unsupported arch/op combination");
2828
+ return {};
2829
+ }
2830
+ return _mm512_inserti32x4(
2831
+ _mm512_inserti32x4(
2832
+ _mm512_inserti32x4(lo, _mm512_extracti32x4_epi32(hi, 0), 1),
2833
+ _mm512_extracti32x4_epi32(hi, 1),
2834
+ 3),
2835
+ _mm512_extracti32x4_epi32(lo, 1),
2836
+ 2);
2837
+ }
2838
+ template <class A>
2839
+ XSIMD_INLINE batch<float, A>
2840
+ zip_lo(batch<float, A> const& self, batch<float, A> const& other, requires_arch<avx512f>) noexcept
2841
+ {
2842
+ auto lo = _mm512_unpacklo_ps(self, other);
2843
+ auto hi = _mm512_unpackhi_ps(self, other);
2844
+ return _mm512_insertf32x4(
2845
+ _mm512_insertf32x4(
2846
+ _mm512_insertf32x4(lo, _mm512_extractf32x4_ps(hi, 0), 1),
2847
+ _mm512_extractf32x4_ps(hi, 1),
2848
+ 3),
2849
+ _mm512_extractf32x4_ps(lo, 1),
2850
+ 2);
2851
+ }
2852
+ template <class A>
2853
+ XSIMD_INLINE batch<double, A>
2854
+ zip_lo(batch<double, A> const& self, batch<double, A> const& other, requires_arch<avx512f>) noexcept
2855
+ {
2856
+ auto lo = _mm512_castpd_ps(_mm512_unpacklo_pd(self, other));
2857
+ auto hi = _mm512_castpd_ps(_mm512_unpackhi_pd(self, other));
2858
+ return _mm512_castps_pd(_mm512_insertf32x4(
2859
+ _mm512_insertf32x4(
2860
+ _mm512_insertf32x4(lo, _mm512_extractf32x4_ps(hi, 0), 1),
2861
+ _mm512_extractf32x4_ps(hi, 1),
2862
+ 3),
2863
+ _mm512_extractf32x4_ps(lo, 1),
2864
+ 2));
2865
+ }
2866
+
2867
+ // widen
2868
+ template <class A, class T>
2869
+ XSIMD_INLINE std::array<batch<widen_t<T>, A>, 2> widen(batch<T, A> const& x, requires_arch<avx512f>) noexcept
2870
+ {
2871
+ __m256i x_lo = detail::lower_half(x);
2872
+ __m256i x_hi = detail::upper_half(x);
2873
+ __m512i lo, hi;
2874
+ XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
2875
+ {
2876
+ XSIMD_IF_CONSTEXPR(std::is_signed<T>::value)
2877
+ {
2878
+ lo = _mm512_cvtepi32_epi64(x_lo);
2879
+ hi = _mm512_cvtepi32_epi64(x_hi);
2880
+ }
2881
+ else
2882
+ {
2883
+ lo = _mm512_cvtepu32_epi64(x_lo);
2884
+ hi = _mm512_cvtepu32_epi64(x_hi);
2885
+ }
2886
+ }
2887
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 2)
2888
+ {
2889
+ XSIMD_IF_CONSTEXPR(std::is_signed<T>::value)
2890
+ {
2891
+ lo = _mm512_cvtepi16_epi32(x_lo);
2892
+ hi = _mm512_cvtepi16_epi32(x_hi);
2893
+ }
2894
+ else
2895
+ {
2896
+ lo = _mm512_cvtepu16_epi32(x_lo);
2897
+ hi = _mm512_cvtepu16_epi32(x_hi);
2898
+ }
2899
+ }
2900
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 1)
2901
+ {
2902
+ auto pair_lo = widen(batch<T, avx2>(x_lo), avx2 {});
2903
+ auto pair_hi = widen(batch<T, avx2>(x_hi), avx2 {});
2904
+ return { detail::merge_avx(pair_lo[0], pair_lo[1]), detail::merge_avx(pair_hi[0], pair_hi[1]) };
2905
+ }
2906
+ return { lo, hi };
2907
+ }
2908
+ template <class A>
2909
+ XSIMD_INLINE std::array<batch<double, A>, 2> widen(batch<float, A> const& x, requires_arch<avx512f>) noexcept
2910
+ {
2911
+ __m512d lo = _mm512_cvtps_pd(detail::lower_half(x));
2912
+ __m512d hi = _mm512_cvtps_pd(detail::upper_half(x));
2913
+ return { lo, hi };
2914
+ }
2915
+
2916
+ }
2917
+ }
2918
+
2919
+ #endif