react-native-executorch 0.10.6 → 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 (237) hide show
  1. package/lib/module/fetcher/telemetry.js +1 -1
  2. package/package.json +1 -1
  3. package/react-native-executorch.podspec +2 -0
  4. package/src/fetcher/telemetry.ts +1 -1
  5. package/third-party/common/phonemis/CMakeLists.txt +70 -14
  6. package/third-party/common/phonemis/README.md +183 -33
  7. package/third-party/common/phonemis/THIRD_PARTY_NOTICES.md +57 -0
  8. package/third-party/common/phonemis/knowledge/code_style.md +642 -0
  9. package/third-party/common/phonemis/licenses/Unicode-3.0.txt +39 -0
  10. package/third-party/common/phonemis/licenses/misaki-Apache-2.0.txt +201 -0
  11. package/third-party/common/phonemis/licenses/nlohmann-json-MIT.txt +21 -0
  12. package/third-party/common/phonemis/licenses/xsimd-BSD-3-Clause.txt +29 -0
  13. package/third-party/common/phonemis/src/phonemis/base/config.h +6 -0
  14. package/third-party/common/phonemis/src/phonemis/base/ipipeline.cpp +75 -0
  15. package/third-party/common/phonemis/src/phonemis/base/ipipeline.h +21 -0
  16. package/third-party/common/phonemis/src/phonemis/base/phonemizer/constants.h +2 -5
  17. package/third-party/common/phonemis/src/phonemis/base/phonemizer/lexicon_phonemizer.cpp +3 -4
  18. package/third-party/common/phonemis/src/phonemis/base/phonemizer/nn/neural_phonemizer.cpp +17 -8
  19. package/third-party/common/phonemis/src/phonemis/base/phonemizer/nn/neural_phonemizer.h +4 -0
  20. package/third-party/common/phonemis/src/phonemis/base/phonemizer/nn/tokenizer.cpp +21 -6
  21. package/third-party/common/phonemis/src/phonemis/base/phonemizer/nn/tokenizer.h +13 -4
  22. package/third-party/common/phonemis/src/phonemis/base/pipeline.cpp +8 -0
  23. package/third-party/common/phonemis/src/phonemis/base/pipeline.h +19 -0
  24. package/third-party/common/phonemis/src/phonemis/base/processor/common/conditions.cpp +37 -0
  25. package/third-party/common/phonemis/src/phonemis/base/processor/common/conditions.h +45 -0
  26. package/third-party/common/phonemis/src/phonemis/base/processor/common/constants.h +10 -0
  27. package/third-party/common/phonemis/src/phonemis/base/processor/common/context.cpp +105 -0
  28. package/third-party/common/phonemis/src/phonemis/base/processor/common/context.h +49 -0
  29. package/third-party/common/phonemis/src/phonemis/base/processor/common/document.cpp +173 -0
  30. package/third-party/common/phonemis/src/phonemis/base/processor/common/document.h +67 -0
  31. package/third-party/common/phonemis/src/phonemis/base/processor/common/text.cpp +75 -0
  32. package/third-party/common/phonemis/src/phonemis/base/processor/common/text.h +60 -0
  33. package/third-party/common/phonemis/src/phonemis/base/processor/common/types.h +18 -0
  34. package/third-party/common/phonemis/src/phonemis/base/processor/config.h +53 -0
  35. package/third-party/common/phonemis/src/phonemis/base/processor/layer.h +9 -7
  36. package/third-party/common/phonemis/src/phonemis/base/processor/layers/normalize/constants.h +20 -0
  37. package/third-party/common/phonemis/src/phonemis/base/processor/layers/normalize/layer.cpp +89 -0
  38. package/third-party/common/phonemis/src/phonemis/base/processor/layers/normalize/layer.h +35 -0
  39. package/third-party/common/phonemis/src/phonemis/base/processor/layers/normalize/types.h +16 -0
  40. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/kind.h +40 -0
  41. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/layer.h +382 -0
  42. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/notation.h +30 -0
  43. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/numerals.cpp +51 -0
  44. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/numerals.h +31 -0
  45. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/pattern.h +30 -0
  46. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/pattern_set.cpp +17 -0
  47. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/pattern_set.h +31 -0
  48. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/patterns.cpp +811 -0
  49. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/patterns.h +285 -0
  50. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/primitives.cpp +64 -0
  51. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/primitives.h +23 -0
  52. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/types.h +94 -0
  53. package/third-party/common/phonemis/src/phonemis/base/processor/layers/sanitizer/layer.cpp +19 -0
  54. package/third-party/common/phonemis/src/phonemis/base/processor/{sanitizer_layer.h → layers/sanitizer/layer.h} +8 -8
  55. package/third-party/common/phonemis/src/phonemis/base/processor/layers/sym2word/layer.cpp +65 -0
  56. package/third-party/common/phonemis/src/phonemis/base/processor/layers/sym2word/layer.h +29 -0
  57. package/third-party/common/phonemis/src/phonemis/base/processor/layers/term2word/layer.cpp +170 -0
  58. package/third-party/common/phonemis/src/phonemis/base/processor/layers/term2word/layer.h +40 -0
  59. package/third-party/common/phonemis/src/phonemis/base/processor/layers/term2word/types.h +25 -0
  60. package/third-party/common/phonemis/src/phonemis/base/processor/layers/trim/layer.cpp +47 -0
  61. package/third-party/common/phonemis/src/phonemis/base/processor/layers/trim/layer.h +19 -0
  62. package/third-party/common/phonemis/src/phonemis/base/processor/preprocessor.cpp +60 -0
  63. package/third-party/common/phonemis/src/phonemis/base/processor/preprocessor.h +45 -0
  64. package/third-party/common/phonemis/src/phonemis/base/processor/processor.cpp +6 -7
  65. package/third-party/common/phonemis/src/phonemis/base/processor/processor.h +14 -10
  66. package/third-party/common/phonemis/src/phonemis/base/tagger/hmm_tagger.cpp +89 -52
  67. package/third-party/common/phonemis/src/phonemis/base/tagger/hmm_tagger.h +16 -9
  68. package/third-party/common/phonemis/src/phonemis/base/tokenizer/tokenizer.cpp +13 -12
  69. package/third-party/common/phonemis/src/phonemis/lang/de/constants.h +183 -19
  70. package/third-party/common/phonemis/src/phonemis/lang/de/num2word.cpp +355 -309
  71. package/third-party/common/phonemis/src/phonemis/lang/de/num2word.h +42 -17
  72. package/third-party/common/phonemis/src/phonemis/lang/de/patterns.cpp +56 -0
  73. package/third-party/common/phonemis/src/phonemis/lang/de/patterns.h +15 -0
  74. package/third-party/common/phonemis/src/phonemis/lang/de/pipeline.h +3 -3
  75. package/third-party/common/phonemis/src/phonemis/lang/en/constants.h +181 -30
  76. package/third-party/common/phonemis/src/phonemis/lang/en/hmm_tagger.cpp +5 -7
  77. package/third-party/common/phonemis/src/phonemis/lang/en/num2word.cpp +232 -135
  78. package/third-party/common/phonemis/src/phonemis/lang/en/num2word.h +41 -16
  79. package/third-party/common/phonemis/src/phonemis/lang/en/pipeline.h +3 -10
  80. package/third-party/common/phonemis/src/phonemis/lang/es/constants.h +182 -60
  81. package/third-party/common/phonemis/src/phonemis/lang/es/num2word.cpp +247 -212
  82. package/third-party/common/phonemis/src/phonemis/lang/es/num2word.h +38 -18
  83. package/third-party/common/phonemis/src/phonemis/lang/es/patterns.cpp +50 -0
  84. package/third-party/common/phonemis/src/phonemis/lang/es/patterns.h +15 -0
  85. package/third-party/common/phonemis/src/phonemis/lang/es/pipeline.h +3 -3
  86. package/third-party/common/phonemis/src/phonemis/lang/fr/constants.h +152 -26
  87. package/third-party/common/phonemis/src/phonemis/lang/fr/num2word.cpp +252 -179
  88. package/third-party/common/phonemis/src/phonemis/lang/fr/num2word.h +38 -15
  89. package/third-party/common/phonemis/src/phonemis/lang/fr/patterns.cpp +83 -0
  90. package/third-party/common/phonemis/src/phonemis/lang/fr/patterns.h +15 -0
  91. package/third-party/common/phonemis/src/phonemis/lang/fr/pipeline.h +3 -3
  92. package/third-party/common/phonemis/src/phonemis/lang/hi/constants.h +62 -10
  93. package/third-party/common/phonemis/src/phonemis/lang/hi/num2word.cpp +74 -123
  94. package/third-party/common/phonemis/src/phonemis/lang/hi/num2word.h +27 -16
  95. package/third-party/common/phonemis/src/phonemis/lang/hi/pipeline.h +5 -3
  96. package/third-party/common/phonemis/src/phonemis/lang/it/constants.h +122 -42
  97. package/third-party/common/phonemis/src/phonemis/lang/it/num2word.cpp +200 -207
  98. package/third-party/common/phonemis/src/phonemis/lang/it/num2word.h +30 -18
  99. package/third-party/common/phonemis/src/phonemis/lang/it/patterns.cpp +25 -0
  100. package/third-party/common/phonemis/src/phonemis/lang/it/patterns.h +15 -0
  101. package/third-party/common/phonemis/src/phonemis/lang/it/pipeline.h +3 -3
  102. package/third-party/common/phonemis/src/phonemis/lang/pl/constants.h +346 -77
  103. package/third-party/common/phonemis/src/phonemis/lang/pl/num2word.cpp +631 -246
  104. package/third-party/common/phonemis/src/phonemis/lang/pl/num2word.h +47 -15
  105. package/third-party/common/phonemis/src/phonemis/lang/pl/pipeline.h +6 -6
  106. package/third-party/common/phonemis/src/phonemis/lang/pt/constants.h +201 -0
  107. package/third-party/common/phonemis/src/phonemis/lang/pt/num2word.cpp +365 -0
  108. package/third-party/common/phonemis/src/phonemis/lang/pt/num2word.h +53 -0
  109. package/third-party/common/phonemis/src/phonemis/lang/pt/pipeline.h +4 -2
  110. package/third-party/common/phonemis/src/phonemis/main.cpp +42 -11
  111. package/third-party/common/phonemis/src/phonemis/protophone/meta.h +24 -0
  112. package/third-party/common/phonemis/src/phonemis/protophone/numeric.h +26 -0
  113. package/third-party/common/phonemis/src/phonemis/protophone/protophone.cpp +525 -0
  114. package/third-party/common/phonemis/src/phonemis/protophone/protophone.h +80 -0
  115. package/third-party/common/phonemis/src/phonemis/protophone/tensor.h +76 -0
  116. package/third-party/common/phonemis/src/phonemis/protophone/tensor_utils.h +89 -0
  117. package/third-party/common/phonemis/src/phonemis/protophone/tensor_view.h +125 -0
  118. package/third-party/common/phonemis/src/phonemis/protophone/types.h +43 -0
  119. package/third-party/common/phonemis/src/phonemis/utils/strings.h +20 -14
  120. package/third-party/common/phonemis/src/phonemis/utils/unicode.h +15 -1
  121. package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_arithmetic.hpp +267 -0
  122. package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_bit.hpp +232 -0
  123. package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_cast.hpp +43 -0
  124. package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_complex.hpp +112 -0
  125. package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_details.hpp +386 -0
  126. package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_logical.hpp +240 -0
  127. package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_math.hpp +2601 -0
  128. package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_memory.hpp +1006 -0
  129. package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_rounding.hpp +72 -0
  130. package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_swizzle.hpp +260 -0
  131. package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_trigo.hpp +996 -0
  132. package/third-party/common/phonemis/src/third-party/xsimd/arch/utils/shifts.hpp +82 -0
  133. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx.hpp +2111 -0
  134. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx2.hpp +1591 -0
  135. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx2_128.hpp +170 -0
  136. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512bw.hpp +724 -0
  137. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512cd.hpp +28 -0
  138. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512dq.hpp +270 -0
  139. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512er.hpp +17 -0
  140. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512f.hpp +2919 -0
  141. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512ifma.hpp +17 -0
  142. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512pf.hpp +17 -0
  143. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512vbmi.hpp +76 -0
  144. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512vbmi2.hpp +130 -0
  145. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512vnni_avx512bw.hpp +17 -0
  146. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512vnni_avx512vbmi2.hpp +17 -0
  147. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx_128.hpp +164 -0
  148. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avxvnni.hpp +17 -0
  149. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_common.hpp +26 -0
  150. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_common_fwd.hpp +127 -0
  151. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_constants.hpp +393 -0
  152. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_emulated.hpp +787 -0
  153. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_fma3_avx.hpp +93 -0
  154. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_fma3_avx2.hpp +46 -0
  155. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_fma3_sse.hpp +97 -0
  156. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_fma4.hpp +92 -0
  157. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_i8mm_neon64.hpp +17 -0
  158. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_isa.hpp +148 -0
  159. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_neon.hpp +3580 -0
  160. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_neon64.hpp +1614 -0
  161. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_rvv.hpp +1515 -0
  162. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_scalar.hpp +1210 -0
  163. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_sse2.hpp +2333 -0
  164. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_sse3.hpp +66 -0
  165. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_sse4_1.hpp +510 -0
  166. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_sse4_2.hpp +44 -0
  167. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_ssse3.hpp +186 -0
  168. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_sve.hpp +1186 -0
  169. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_vsx.hpp +947 -0
  170. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_vxe.hpp +787 -0
  171. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_wasm.hpp +1819 -0
  172. package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_arch.hpp +242 -0
  173. package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_config.hpp +633 -0
  174. package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_cpu_features.hpp +50 -0
  175. package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_cpu_features_arm.hpp +132 -0
  176. package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_cpu_features_ppc.hpp +54 -0
  177. package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_cpu_features_riscv.hpp +95 -0
  178. package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_cpu_features_s390x.hpp +56 -0
  179. package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_cpu_features_x86.hpp +1121 -0
  180. package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_cpuid.hpp +144 -0
  181. package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_getauxval.hpp +159 -0
  182. package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_macros.hpp +78 -0
  183. package/third-party/common/phonemis/src/third-party/xsimd/math/xsimd_rem_pio2.hpp +707 -0
  184. package/third-party/common/phonemis/src/third-party/xsimd/memory/xsimd_aligned_allocator.hpp +349 -0
  185. package/third-party/common/phonemis/src/third-party/xsimd/memory/xsimd_alignment.hpp +102 -0
  186. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_all_registers.hpp +57 -0
  187. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_api.hpp +3106 -0
  188. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx2_register.hpp +57 -0
  189. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512bw_register.hpp +51 -0
  190. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512cd_register.hpp +51 -0
  191. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512dq_register.hpp +51 -0
  192. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512er_register.hpp +51 -0
  193. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512f_register.hpp +77 -0
  194. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512ifma_register.hpp +51 -0
  195. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512pf_register.hpp +51 -0
  196. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512vbmi2_register.hpp +51 -0
  197. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512vbmi_register.hpp +51 -0
  198. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512vnni_avx512bw_register.hpp +54 -0
  199. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512vnni_avx512vbmi2_register.hpp +53 -0
  200. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx_register.hpp +79 -0
  201. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avxvnni_register.hpp +44 -0
  202. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_batch.hpp +1666 -0
  203. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_batch_constant.hpp +572 -0
  204. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_batch_fwd.hpp +41 -0
  205. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_common_arch.hpp +49 -0
  206. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_emulated_register.hpp +80 -0
  207. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_fma3_avx2_register.hpp +50 -0
  208. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_fma3_avx_register.hpp +50 -0
  209. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_fma3_sse_register.hpp +50 -0
  210. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_fma4_register.hpp +50 -0
  211. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_i8mm_neon64_register.hpp +55 -0
  212. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_neon64_register.hpp +55 -0
  213. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_neon_register.hpp +130 -0
  214. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_register.hpp +96 -0
  215. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_rvv_register.hpp +491 -0
  216. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_sse2_register.hpp +59 -0
  217. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_sse3_register.hpp +49 -0
  218. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_sse4_1_register.hpp +48 -0
  219. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_sse4_2_register.hpp +48 -0
  220. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_ssse3_register.hpp +48 -0
  221. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_sve_register.hpp +216 -0
  222. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_traits.hpp +409 -0
  223. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_utils.hpp +462 -0
  224. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_vsx_register.hpp +84 -0
  225. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_vxe_register.hpp +86 -0
  226. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_wasm_register.hpp +59 -0
  227. package/third-party/common/phonemis/src/third-party/xsimd/utils/bits.hpp +122 -0
  228. package/third-party/common/phonemis/src/third-party/xsimd/utils/xsimd_type_traits.hpp +145 -0
  229. package/third-party/common/phonemis/src/third-party/xsimd/xsimd.hpp +43 -0
  230. package/third-party/common/phonemis/src/phonemis/base/processor/constants.h +0 -11
  231. package/third-party/common/phonemis/src/phonemis/base/processor/num2word/config.h +0 -16
  232. package/third-party/common/phonemis/src/phonemis/base/processor/num2word/layer.cpp +0 -271
  233. package/third-party/common/phonemis/src/phonemis/base/processor/num2word/layer.h +0 -45
  234. package/third-party/common/phonemis/src/phonemis/base/processor/num2word/types.h +0 -29
  235. package/third-party/common/phonemis/src/phonemis/base/processor/sanitizer_layer.cpp +0 -22
  236. package/third-party/common/phonemis/src/phonemis/base/processor/trim_layer.cpp +0 -40
  237. package/third-party/common/phonemis/src/phonemis/base/processor/trim_layer.h +0 -22
@@ -0,0 +1,2111 @@
1
+ /***************************************************************************
2
+ * Copyright (c) Johan Mabille, Sylvain Corlay, Wolf Vollprecht and *
3
+ * Martin Renou *
4
+ * Copyright (c) QuantStack *
5
+ * Copyright (c) Serge Guelton *
6
+ * Copyright (c) Marco Barbone *
7
+ * *
8
+ * Distributed under the terms of the BSD 3-Clause License. *
9
+ * *
10
+ * The full license is in the file LICENSE, distributed with this software. *
11
+ ****************************************************************************/
12
+
13
+ #ifndef XSIMD_AVX_HPP
14
+ #define XSIMD_AVX_HPP
15
+
16
+ #include <complex>
17
+ #include <limits>
18
+ #include <type_traits>
19
+
20
+ #include "../types/xsimd_avx_register.hpp"
21
+ #include "../types/xsimd_batch_constant.hpp"
22
+
23
+ namespace xsimd
24
+ {
25
+ namespace kernel
26
+ {
27
+ using namespace types;
28
+
29
+ // fwd
30
+ template <class A, class T, size_t I>
31
+ XSIMD_INLINE batch<T, A> insert(batch<T, A> const& self, T val, index<I>, requires_arch<common>) noexcept;
32
+
33
+ template <class A>
34
+ XSIMD_INLINE void transpose(batch<uint16_t, A>* matrix_begin, batch<uint16_t, A>* matrix_end, requires_arch<common>) noexcept;
35
+ template <class A>
36
+ XSIMD_INLINE void transpose(batch<uint8_t, A>* matrix_begin, batch<uint8_t, A>* matrix_end, requires_arch<common>) noexcept;
37
+
38
+ namespace detail
39
+ {
40
+ XSIMD_INLINE __m128i lower_half(__m256i self) noexcept
41
+ {
42
+ return _mm256_castsi256_si128(self);
43
+ }
44
+ XSIMD_INLINE __m128 lower_half(__m256 self) noexcept
45
+ {
46
+ return _mm256_castps256_ps128(self);
47
+ }
48
+ XSIMD_INLINE __m128d lower_half(__m256d self) noexcept
49
+ {
50
+ return _mm256_castpd256_pd128(self);
51
+ }
52
+ XSIMD_INLINE __m128i upper_half(__m256i self) noexcept
53
+ {
54
+ return _mm256_extractf128_si256(self, 1);
55
+ }
56
+ XSIMD_INLINE __m128 upper_half(__m256 self) noexcept
57
+ {
58
+ return _mm256_extractf128_ps(self, 1);
59
+ }
60
+ XSIMD_INLINE __m128d upper_half(__m256d self) noexcept
61
+ {
62
+ return _mm256_extractf128_pd(self, 1);
63
+ }
64
+ XSIMD_INLINE __m256i merge_sse(__m128i low, __m128i high) noexcept
65
+ {
66
+ return _mm256_insertf128_si256(_mm256_castsi128_si256(low), high, 1);
67
+ }
68
+ XSIMD_INLINE __m256 merge_sse(__m128 low, __m128 high) noexcept
69
+ {
70
+ return _mm256_insertf128_ps(_mm256_castps128_ps256(low), high, 1);
71
+ }
72
+ XSIMD_INLINE __m256d merge_sse(__m128d low, __m128d high) noexcept
73
+ {
74
+ return _mm256_insertf128_pd(_mm256_castpd128_pd256(low), high, 1);
75
+ }
76
+ template <class F>
77
+ XSIMD_INLINE __m256i fwd_to_sse(F f, __m256i self) noexcept
78
+ {
79
+ __m128i self_low = lower_half(self), self_high = upper_half(self);
80
+ __m128i res_low = f(self_low);
81
+ __m128i res_high = f(self_high);
82
+ return merge_sse(res_low, res_high);
83
+ }
84
+ template <class F>
85
+ XSIMD_INLINE __m256i fwd_to_sse(F f, __m256i self, __m256i other) noexcept
86
+ {
87
+ __m128i self_low = lower_half(self), self_high = upper_half(self),
88
+ other_low = lower_half(other), other_high = upper_half(other);
89
+ __m128i res_low = f(self_low, other_low);
90
+ __m128i res_high = f(self_high, other_high);
91
+ return merge_sse(res_low, res_high);
92
+ }
93
+ template <class F>
94
+ XSIMD_INLINE __m256i fwd_to_sse(F f, __m256i self, int32_t other) noexcept
95
+ {
96
+ __m128i self_low = lower_half(self), self_high = upper_half(self);
97
+ __m128i res_low = f(self_low, other);
98
+ __m128i res_high = f(self_high, other);
99
+ return merge_sse(res_low, res_high);
100
+ }
101
+ }
102
+
103
+ // abs
104
+ template <class A>
105
+ XSIMD_INLINE batch<float, A> abs(batch<float, A> const& self, requires_arch<avx>) noexcept
106
+ {
107
+ __m256 sign_mask = _mm256_set1_ps(-0.f); // -0.f = 1 << 31
108
+ return _mm256_andnot_ps(sign_mask, self);
109
+ }
110
+ template <class A>
111
+ XSIMD_INLINE batch<double, A> abs(batch<double, A> const& self, requires_arch<avx>) noexcept
112
+ {
113
+ __m256d sign_mask = _mm256_set1_pd(-0.f); // -0.f = 1 << 31
114
+ return _mm256_andnot_pd(sign_mask, self);
115
+ }
116
+
117
+ // add
118
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
119
+ XSIMD_INLINE batch<T, A> add(batch<T, A> const& self, batch<T, A> const& other, requires_arch<avx>) noexcept
120
+ {
121
+ return detail::fwd_to_sse([](__m128i s, __m128i o) noexcept
122
+ { return add(batch<T, sse4_2>(s), batch<T, sse4_2>(o)); },
123
+ self, other);
124
+ }
125
+ template <class A>
126
+ XSIMD_INLINE batch<float, A> add(batch<float, A> const& self, batch<float, A> const& other, requires_arch<avx>) noexcept
127
+ {
128
+ return _mm256_add_ps(self, other);
129
+ }
130
+ template <class A>
131
+ XSIMD_INLINE batch<double, A> add(batch<double, A> const& self, batch<double, A> const& other, requires_arch<avx>) noexcept
132
+ {
133
+ return _mm256_add_pd(self, other);
134
+ }
135
+
136
+ // all
137
+ template <class A>
138
+ XSIMD_INLINE bool all(batch_bool<float, A> const& self, requires_arch<avx>) noexcept
139
+ {
140
+ return _mm256_testc_ps(self, batch_bool<float, A>(true)) != 0;
141
+ }
142
+ template <class A>
143
+ XSIMD_INLINE bool all(batch_bool<double, A> const& self, requires_arch<avx>) noexcept
144
+ {
145
+ return _mm256_testc_pd(self, batch_bool<double, A>(true)) != 0;
146
+ }
147
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
148
+ XSIMD_INLINE bool all(batch_bool<T, A> const& self, requires_arch<avx>) noexcept
149
+ {
150
+ return _mm256_testc_si256(self, batch_bool<T, A>(true)) != 0;
151
+ }
152
+
153
+ // any
154
+ template <class A>
155
+ XSIMD_INLINE bool any(batch_bool<float, A> const& self, requires_arch<avx>) noexcept
156
+ {
157
+ return !_mm256_testz_ps(self, self);
158
+ }
159
+ template <class A>
160
+ XSIMD_INLINE bool any(batch_bool<double, A> const& self, requires_arch<avx>) noexcept
161
+ {
162
+ return !_mm256_testz_pd(self, self);
163
+ }
164
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
165
+ XSIMD_INLINE bool any(batch_bool<T, A> const& self, requires_arch<avx>) noexcept
166
+ {
167
+ return !_mm256_testz_si256(self, self);
168
+ }
169
+
170
+ // batch_bool_cast
171
+ template <class A, class T_out, class T_in>
172
+ 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<avx>) noexcept
173
+ {
174
+ return { bitwise_cast<T_out>(batch<T_in, A>(self.data)).data };
175
+ }
176
+
177
+ // bitwise_and
178
+ template <class A>
179
+ XSIMD_INLINE batch<float, A> bitwise_and(batch<float, A> const& self, batch<float, A> const& other, requires_arch<avx>) noexcept
180
+ {
181
+ return _mm256_and_ps(self, other);
182
+ }
183
+ template <class A>
184
+ XSIMD_INLINE batch<double, A> bitwise_and(batch<double, A> const& self, batch<double, A> const& other, requires_arch<avx>) noexcept
185
+ {
186
+ return _mm256_and_pd(self, other);
187
+ }
188
+
189
+ template <class A>
190
+ XSIMD_INLINE batch_bool<float, A> bitwise_and(batch_bool<float, A> const& self, batch_bool<float, A> const& other, requires_arch<avx>) noexcept
191
+ {
192
+ return _mm256_and_ps(self, other);
193
+ }
194
+ template <class A>
195
+ XSIMD_INLINE batch_bool<double, A> bitwise_and(batch_bool<double, A> const& self, batch_bool<double, A> const& other, requires_arch<avx>) noexcept
196
+ {
197
+ return _mm256_and_pd(self, other);
198
+ }
199
+
200
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
201
+ XSIMD_INLINE batch<T, A> bitwise_and(batch<T, A> const& self, batch<T, A> const& other, requires_arch<avx>) noexcept
202
+ {
203
+ return detail::fwd_to_sse([](__m128i s, __m128i o) noexcept
204
+ { return bitwise_and(batch<T, sse4_2>(s), batch<T, sse4_2>(o)); },
205
+ self, other);
206
+ }
207
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
208
+ XSIMD_INLINE batch_bool<T, A> bitwise_and(batch_bool<T, A> const& self, batch_bool<T, A> const& other, requires_arch<avx>) noexcept
209
+ {
210
+ return detail::fwd_to_sse([](__m128i s, __m128i o) noexcept
211
+ { return bitwise_and(batch<T, sse4_2>(s), batch<T, sse4_2>(o)); },
212
+ self, other);
213
+ }
214
+
215
+ // bitwise_andnot
216
+ template <class A>
217
+ XSIMD_INLINE batch<float, A> bitwise_andnot(batch<float, A> const& self, batch<float, A> const& other, requires_arch<avx>) noexcept
218
+ {
219
+ return _mm256_andnot_ps(other, self);
220
+ }
221
+ template <class A>
222
+ XSIMD_INLINE batch<double, A> bitwise_andnot(batch<double, A> const& self, batch<double, A> const& other, requires_arch<avx>) noexcept
223
+ {
224
+ return _mm256_andnot_pd(other, self);
225
+ }
226
+
227
+ template <class A>
228
+ XSIMD_INLINE batch_bool<float, A> bitwise_andnot(batch_bool<float, A> const& self, batch_bool<float, A> const& other, requires_arch<avx>) noexcept
229
+ {
230
+ return _mm256_andnot_ps(other, self);
231
+ }
232
+ template <class A>
233
+ XSIMD_INLINE batch_bool<double, A> bitwise_andnot(batch_bool<double, A> const& self, batch_bool<double, A> const& other, requires_arch<avx>) noexcept
234
+ {
235
+ return _mm256_andnot_pd(other, self);
236
+ }
237
+
238
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
239
+ XSIMD_INLINE batch<T, A> bitwise_andnot(batch<T, A> const& self, batch<T, A> const& other, requires_arch<avx>) noexcept
240
+ {
241
+ return detail::fwd_to_sse([](__m128i s, __m128i o) noexcept
242
+ { return bitwise_andnot(batch<T, sse4_2>(s), batch<T, sse4_2>(o)); },
243
+ self, other);
244
+ }
245
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
246
+ XSIMD_INLINE batch_bool<T, A> bitwise_andnot(batch_bool<T, A> const& self, batch_bool<T, A> const& other, requires_arch<avx>) noexcept
247
+ {
248
+ return detail::fwd_to_sse([](__m128i s, __m128i o) noexcept
249
+ { return bitwise_andnot(batch<T, sse4_2>(s), batch<T, sse4_2>(o)); },
250
+ self, other);
251
+ }
252
+
253
+ // bitwise_lshift
254
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
255
+ XSIMD_INLINE batch<T, A> bitwise_lshift(batch<T, A> const& self, int32_t other, requires_arch<avx>) noexcept
256
+ {
257
+ return detail::fwd_to_sse([](__m128i s, int32_t o) noexcept
258
+ { return bitwise_lshift(batch<T, sse4_2>(s), o, sse4_2 {}); },
259
+ self, other);
260
+ }
261
+
262
+ // bitwise_not
263
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
264
+ XSIMD_INLINE batch<T, A> bitwise_not(batch<T, A> const& self, requires_arch<avx>) noexcept
265
+ {
266
+ return detail::fwd_to_sse([](__m128i s) noexcept
267
+ { return bitwise_not(batch<T, sse4_2>(s), sse4_2 {}); },
268
+ self);
269
+ }
270
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
271
+ XSIMD_INLINE batch_bool<T, A> bitwise_not(batch_bool<T, A> const& self, requires_arch<avx>) noexcept
272
+ {
273
+ return detail::fwd_to_sse([](__m128i s) noexcept
274
+ { return bitwise_not(batch_bool<T, sse4_2>(s), sse4_2 {}); },
275
+ self);
276
+ }
277
+
278
+ // bitwise_or
279
+ template <class A>
280
+ XSIMD_INLINE batch<float, A> bitwise_or(batch<float, A> const& self, batch<float, A> const& other, requires_arch<avx>) noexcept
281
+ {
282
+ return _mm256_or_ps(self, other);
283
+ }
284
+ template <class A>
285
+ XSIMD_INLINE batch<double, A> bitwise_or(batch<double, A> const& self, batch<double, A> const& other, requires_arch<avx>) noexcept
286
+ {
287
+ return _mm256_or_pd(self, other);
288
+ }
289
+ template <class A>
290
+ XSIMD_INLINE batch_bool<float, A> bitwise_or(batch_bool<float, A> const& self, batch_bool<float, A> const& other, requires_arch<avx>) noexcept
291
+ {
292
+ return _mm256_or_ps(self, other);
293
+ }
294
+ template <class A>
295
+ XSIMD_INLINE batch_bool<double, A> bitwise_or(batch_bool<double, A> const& self, batch_bool<double, A> const& other, requires_arch<avx>) noexcept
296
+ {
297
+ return _mm256_or_pd(self, other);
298
+ }
299
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
300
+ XSIMD_INLINE batch<T, A> bitwise_or(batch<T, A> const& self, batch<T, A> const& other, requires_arch<avx>) noexcept
301
+ {
302
+ return detail::fwd_to_sse([](__m128i s, __m128i o) noexcept
303
+ { return bitwise_or(batch<T, sse4_2>(s), batch<T, sse4_2>(o)); },
304
+ self, other);
305
+ }
306
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
307
+ XSIMD_INLINE batch_bool<T, A> bitwise_or(batch_bool<T, A> const& self, batch_bool<T, A> const& other, requires_arch<avx>) noexcept
308
+ {
309
+ return detail::fwd_to_sse([](__m128i s, __m128i o) noexcept
310
+ { return bitwise_or(batch_bool<T, sse4_2>(s), batch_bool<T, sse4_2>(o)); },
311
+ self, other);
312
+ }
313
+
314
+ // bitwise_rshift
315
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
316
+ XSIMD_INLINE batch<T, A> bitwise_rshift(batch<T, A> const& self, int32_t other, requires_arch<avx>) noexcept
317
+ {
318
+ return detail::fwd_to_sse([](__m128i s, int32_t o) noexcept
319
+ { return bitwise_rshift(batch<T, sse4_2>(s), o, sse4_2 {}); },
320
+ self, other);
321
+ }
322
+
323
+ // bitwise_xor
324
+ template <class A>
325
+ XSIMD_INLINE batch<float, A> bitwise_xor(batch<float, A> const& self, batch<float, A> const& other, requires_arch<avx>) noexcept
326
+ {
327
+ return _mm256_xor_ps(self, other);
328
+ }
329
+ template <class A>
330
+ XSIMD_INLINE batch<double, A> bitwise_xor(batch<double, A> const& self, batch<double, A> const& other, requires_arch<avx>) noexcept
331
+ {
332
+ return _mm256_xor_pd(self, other);
333
+ }
334
+ template <class A>
335
+ XSIMD_INLINE batch_bool<float, A> bitwise_xor(batch_bool<float, A> const& self, batch_bool<float, A> const& other, requires_arch<avx>) noexcept
336
+ {
337
+ return _mm256_xor_ps(self, other);
338
+ }
339
+ template <class A>
340
+ XSIMD_INLINE batch_bool<double, A> bitwise_xor(batch_bool<double, A> const& self, batch_bool<double, A> const& other, requires_arch<avx>) noexcept
341
+ {
342
+ return _mm256_xor_pd(self, other);
343
+ }
344
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
345
+ XSIMD_INLINE batch<T, A> bitwise_xor(batch<T, A> const& self, batch<T, A> const& other, requires_arch<avx>) noexcept
346
+ {
347
+ return detail::fwd_to_sse([](__m128i s, __m128i o) noexcept
348
+ { return bitwise_xor(batch<T, sse4_2>(s), batch<T, sse4_2>(o), sse4_2 {}); },
349
+ self, other);
350
+ }
351
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
352
+ XSIMD_INLINE batch<T, A> bitwise_xor(batch_bool<T, A> const& self, batch_bool<T, A> const& other, requires_arch<avx>) noexcept
353
+ {
354
+ return detail::fwd_to_sse([](__m128i s, __m128i o) noexcept
355
+ { return bitwise_xor(batch_bool<T, sse4_2>(s), batch_bool<T, sse4_2>(o), sse4_2 {}); },
356
+ self, other);
357
+ }
358
+
359
+ // bitwise_cast
360
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
361
+ XSIMD_INLINE batch<float, A> bitwise_cast(batch<T, A> const& self, batch<float, A> const&, requires_arch<avx>) noexcept
362
+ {
363
+ return _mm256_castsi256_ps(self);
364
+ }
365
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
366
+ XSIMD_INLINE batch<double, A> bitwise_cast(batch<T, A> const& self, batch<double, A> const&, requires_arch<avx>) noexcept
367
+ {
368
+ return _mm256_castsi256_pd(self);
369
+ }
370
+ template <class A, class T, class Tp, class = std::enable_if_t<std::is_integral<std::common_type_t<T, Tp>>::value>>
371
+ XSIMD_INLINE batch<Tp, A> bitwise_cast(batch<T, A> const& self, batch<Tp, A> const&, requires_arch<avx>) noexcept
372
+ {
373
+ return batch<Tp, A>(self.data);
374
+ }
375
+ template <class A>
376
+ XSIMD_INLINE batch<double, A> bitwise_cast(batch<float, A> const& self, batch<double, A> const&, requires_arch<avx>) noexcept
377
+ {
378
+ return _mm256_castps_pd(self);
379
+ }
380
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
381
+ XSIMD_INLINE batch<T, A> bitwise_cast(batch<float, A> const& self, batch<T, A> const&, requires_arch<avx>) noexcept
382
+ {
383
+ return _mm256_castps_si256(self);
384
+ }
385
+ template <class A>
386
+ XSIMD_INLINE batch<float, A> bitwise_cast(batch<double, A> const& self, batch<float, A> const&, requires_arch<avx>) noexcept
387
+ {
388
+ return _mm256_castpd_ps(self);
389
+ }
390
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
391
+ XSIMD_INLINE batch<T, A> bitwise_cast(batch<double, A> const& self, batch<T, A> const&, requires_arch<avx>) noexcept
392
+ {
393
+ return _mm256_castpd_si256(self);
394
+ }
395
+
396
+ // bitwise_not
397
+ template <class A>
398
+ XSIMD_INLINE batch<float, A> bitwise_not(batch<float, A> const& self, requires_arch<avx>) noexcept
399
+ {
400
+ return _mm256_xor_ps(self, _mm256_castsi256_ps(_mm256_set1_epi32(-1)));
401
+ }
402
+ template <class A>
403
+ XSIMD_INLINE batch<double, A> bitwise_not(batch<double, A> const& self, requires_arch<avx>) noexcept
404
+ {
405
+ return _mm256_xor_pd(self, _mm256_castsi256_pd(_mm256_set1_epi32(-1)));
406
+ }
407
+ template <class A>
408
+ XSIMD_INLINE batch_bool<float, A> bitwise_not(batch_bool<float, A> const& self, requires_arch<avx>) noexcept
409
+ {
410
+ return _mm256_xor_ps(self, _mm256_castsi256_ps(_mm256_set1_epi32(-1)));
411
+ }
412
+ template <class A>
413
+ XSIMD_INLINE batch_bool<double, A> bitwise_not(batch_bool<double, A> const& self, requires_arch<avx>) noexcept
414
+ {
415
+ return _mm256_xor_pd(self, _mm256_castsi256_pd(_mm256_set1_epi32(-1)));
416
+ }
417
+
418
+ // broadcast
419
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
420
+ XSIMD_INLINE batch<T, A> broadcast(T val, requires_arch<avx>) noexcept
421
+ {
422
+ XSIMD_IF_CONSTEXPR(sizeof(T) == 1)
423
+ {
424
+ return _mm256_set1_epi8(val);
425
+ }
426
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 2)
427
+ {
428
+ return _mm256_set1_epi16(val);
429
+ }
430
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
431
+ {
432
+ return _mm256_set1_epi32(val);
433
+ }
434
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 8)
435
+ {
436
+ return _mm256_set1_epi64x(val);
437
+ }
438
+ else
439
+ {
440
+ assert(false && "unsupported");
441
+ return {};
442
+ }
443
+ }
444
+ template <class A>
445
+ XSIMD_INLINE batch<float, A> broadcast(float val, requires_arch<avx>) noexcept
446
+ {
447
+ return _mm256_set1_ps(val);
448
+ }
449
+ template <class A>
450
+ XSIMD_INLINE batch<double, A> broadcast(double val, requires_arch<avx>) noexcept
451
+ {
452
+ return _mm256_set1_pd(val);
453
+ }
454
+
455
+ // ceil
456
+ template <class A>
457
+ XSIMD_INLINE batch<float, A> ceil(batch<float, A> const& self, requires_arch<avx>) noexcept
458
+ {
459
+ return _mm256_ceil_ps(self);
460
+ }
461
+ template <class A>
462
+ XSIMD_INLINE batch<double, A> ceil(batch<double, A> const& self, requires_arch<avx>) noexcept
463
+ {
464
+ return _mm256_ceil_pd(self);
465
+ }
466
+
467
+ namespace detail
468
+ {
469
+ // On clang, _mm256_extractf128_ps is built upon build_shufflevector
470
+ // which require index parameter to be a constant
471
+ template <int index, class B>
472
+ XSIMD_INLINE B get_half_complex_f(const B& real, const B& imag) noexcept
473
+ {
474
+ __m128 tmp0 = _mm256_extractf128_ps(real, index);
475
+ __m128 tmp1 = _mm256_extractf128_ps(imag, index);
476
+ __m128 tmp2 = _mm_unpackhi_ps(tmp0, tmp1);
477
+ tmp0 = _mm_unpacklo_ps(tmp0, tmp1);
478
+ __m256 res = real;
479
+ res = _mm256_insertf128_ps(res, tmp0, 0);
480
+ res = _mm256_insertf128_ps(res, tmp2, 1);
481
+ return res;
482
+ }
483
+ template <int index, class B>
484
+ XSIMD_INLINE B get_half_complex_d(const B& real, const B& imag) noexcept
485
+ {
486
+ __m128d tmp0 = _mm256_extractf128_pd(real, index);
487
+ __m128d tmp1 = _mm256_extractf128_pd(imag, index);
488
+ __m128d tmp2 = _mm_unpackhi_pd(tmp0, tmp1);
489
+ tmp0 = _mm_unpacklo_pd(tmp0, tmp1);
490
+ __m256d res = real;
491
+ res = _mm256_insertf128_pd(res, tmp0, 0);
492
+ res = _mm256_insertf128_pd(res, tmp2, 1);
493
+ return res;
494
+ }
495
+
496
+ // complex_low
497
+ template <class A>
498
+ XSIMD_INLINE batch<float, A> complex_low(batch<std::complex<float>, A> const& self, requires_arch<avx>) noexcept
499
+ {
500
+ return get_half_complex_f<0>(self.real(), self.imag());
501
+ }
502
+ template <class A>
503
+ XSIMD_INLINE batch<double, A> complex_low(batch<std::complex<double>, A> const& self, requires_arch<avx>) noexcept
504
+ {
505
+ return get_half_complex_d<0>(self.real(), self.imag());
506
+ }
507
+
508
+ // complex_high
509
+ template <class A>
510
+ XSIMD_INLINE batch<float, A> complex_high(batch<std::complex<float>, A> const& self, requires_arch<avx>) noexcept
511
+ {
512
+ return get_half_complex_f<1>(self.real(), self.imag());
513
+ }
514
+ template <class A>
515
+ XSIMD_INLINE batch<double, A> complex_high(batch<std::complex<double>, A> const& self, requires_arch<avx>) noexcept
516
+ {
517
+ return get_half_complex_d<1>(self.real(), self.imag());
518
+ }
519
+ }
520
+
521
+ // fast_cast
522
+ namespace detail
523
+ {
524
+ template <class A>
525
+ XSIMD_INLINE batch<float, A> fast_cast(batch<int32_t, A> const& self, batch<float, A> const&, requires_arch<avx>) noexcept
526
+ {
527
+ return _mm256_cvtepi32_ps(self);
528
+ }
529
+
530
+ template <class A>
531
+ XSIMD_INLINE batch<int32_t, A> fast_cast(batch<float, A> const& self, batch<int32_t, A> const&, requires_arch<avx>) noexcept
532
+ {
533
+ return _mm256_cvttps_epi32(self);
534
+ }
535
+ }
536
+
537
+ // decr_if
538
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
539
+ XSIMD_INLINE batch<T, A> decr_if(batch<T, A> const& self, batch_bool<T, A> const& mask, requires_arch<avx>) noexcept
540
+ {
541
+ return self + batch<T, A>(mask.data);
542
+ }
543
+
544
+ // div
545
+ template <class A>
546
+ XSIMD_INLINE batch<float, A> div(batch<float, A> const& self, batch<float, A> const& other, requires_arch<avx>) noexcept
547
+ {
548
+ return _mm256_div_ps(self, other);
549
+ }
550
+ template <class A>
551
+ XSIMD_INLINE batch<double, A> div(batch<double, A> const& self, batch<double, A> const& other, requires_arch<avx>) noexcept
552
+ {
553
+ return _mm256_div_pd(self, other);
554
+ }
555
+
556
+ // eq
557
+ template <class A>
558
+ XSIMD_INLINE batch_bool<float, A> eq(batch<float, A> const& self, batch<float, A> const& other, requires_arch<avx>) noexcept
559
+ {
560
+ return _mm256_cmp_ps(self, other, _CMP_EQ_OQ);
561
+ }
562
+ template <class A>
563
+ XSIMD_INLINE batch_bool<double, A> eq(batch<double, A> const& self, batch<double, A> const& other, requires_arch<avx>) noexcept
564
+ {
565
+ return _mm256_cmp_pd(self, other, _CMP_EQ_OQ);
566
+ }
567
+ template <class A>
568
+ XSIMD_INLINE batch_bool<float, A> eq(batch_bool<float, A> const& self, batch_bool<float, A> const& other, requires_arch<avx>) noexcept
569
+ {
570
+ return ~(self != other);
571
+ }
572
+ template <class A>
573
+ XSIMD_INLINE batch_bool<double, A> eq(batch_bool<double, A> const& self, batch_bool<double, A> const& other, requires_arch<avx>) noexcept
574
+ {
575
+ return ~(self != other);
576
+ }
577
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
578
+ XSIMD_INLINE batch_bool<T, A> eq(batch<T, A> const& self, batch<T, A> const& other, requires_arch<avx>) noexcept
579
+ {
580
+ return detail::fwd_to_sse([](__m128i s, __m128i o) noexcept
581
+ { return eq(batch<T, sse4_2>(s), batch<T, sse4_2>(o), sse4_2 {}); },
582
+ self, other);
583
+ }
584
+
585
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
586
+ XSIMD_INLINE batch_bool<T, A> eq(batch_bool<T, A> const& self, batch_bool<T, A> const& other, requires_arch<avx>) noexcept
587
+ {
588
+ return ~(self != other);
589
+ }
590
+
591
+ // floor
592
+ template <class A>
593
+ XSIMD_INLINE batch<float, A> floor(batch<float, A> const& self, requires_arch<avx>) noexcept
594
+ {
595
+ return _mm256_floor_ps(self);
596
+ }
597
+ template <class A>
598
+ XSIMD_INLINE batch<double, A> floor(batch<double, A> const& self, requires_arch<avx>) noexcept
599
+ {
600
+ return _mm256_floor_pd(self);
601
+ }
602
+
603
+ // from_mask
604
+ template <class A>
605
+ XSIMD_INLINE batch_bool<float, A> from_mask(batch_bool<float, A> const&, uint64_t mask, requires_arch<avx>) noexcept
606
+ {
607
+ alignas(A::alignment()) static const uint64_t lut32[] = {
608
+ 0x0000000000000000ul,
609
+ 0x00000000FFFFFFFFul,
610
+ 0xFFFFFFFF00000000ul,
611
+ 0xFFFFFFFFFFFFFFFFul,
612
+ };
613
+ assert(!(mask & ~0xFFul) && "inbound mask");
614
+ return _mm256_castsi256_ps(_mm256_setr_epi64x(lut32[mask & 0x3], lut32[(mask >> 2) & 0x3], lut32[(mask >> 4) & 0x3], lut32[mask >> 6]));
615
+ }
616
+ template <class A>
617
+ XSIMD_INLINE batch_bool<double, A> from_mask(batch_bool<double, A> const&, uint64_t mask, requires_arch<avx>) noexcept
618
+ {
619
+ alignas(A::alignment()) static const uint64_t lut64[][4] = {
620
+ { 0x0000000000000000ul, 0x0000000000000000ul, 0x0000000000000000ul, 0x0000000000000000ul },
621
+ { 0xFFFFFFFFFFFFFFFFul, 0x0000000000000000ul, 0x0000000000000000ul, 0x0000000000000000ul },
622
+ { 0x0000000000000000ul, 0xFFFFFFFFFFFFFFFFul, 0x0000000000000000ul, 0x0000000000000000ul },
623
+ { 0xFFFFFFFFFFFFFFFFul, 0xFFFFFFFFFFFFFFFFul, 0x0000000000000000ul, 0x0000000000000000ul },
624
+ { 0x0000000000000000ul, 0x0000000000000000ul, 0xFFFFFFFFFFFFFFFFul, 0x0000000000000000ul },
625
+ { 0xFFFFFFFFFFFFFFFFul, 0x0000000000000000ul, 0xFFFFFFFFFFFFFFFFul, 0x0000000000000000ul },
626
+ { 0x0000000000000000ul, 0xFFFFFFFFFFFFFFFFul, 0xFFFFFFFFFFFFFFFFul, 0x0000000000000000ul },
627
+ { 0xFFFFFFFFFFFFFFFFul, 0xFFFFFFFFFFFFFFFFul, 0xFFFFFFFFFFFFFFFFul, 0x0000000000000000ul },
628
+ { 0x0000000000000000ul, 0x0000000000000000ul, 0x0000000000000000ul, 0xFFFFFFFFFFFFFFFFul },
629
+ { 0xFFFFFFFFFFFFFFFFul, 0x0000000000000000ul, 0x0000000000000000ul, 0xFFFFFFFFFFFFFFFFul },
630
+ { 0x0000000000000000ul, 0xFFFFFFFFFFFFFFFFul, 0x0000000000000000ul, 0xFFFFFFFFFFFFFFFFul },
631
+ { 0xFFFFFFFFFFFFFFFFul, 0xFFFFFFFFFFFFFFFFul, 0x0000000000000000ul, 0xFFFFFFFFFFFFFFFFul },
632
+ { 0x0000000000000000ul, 0x0000000000000000ul, 0xFFFFFFFFFFFFFFFFul, 0xFFFFFFFFFFFFFFFFul },
633
+ { 0xFFFFFFFFFFFFFFFFul, 0x0000000000000000ul, 0xFFFFFFFFFFFFFFFFul, 0xFFFFFFFFFFFFFFFFul },
634
+ { 0x0000000000000000ul, 0xFFFFFFFFFFFFFFFFul, 0xFFFFFFFFFFFFFFFFul, 0xFFFFFFFFFFFFFFFFul },
635
+ { 0xFFFFFFFFFFFFFFFFul, 0xFFFFFFFFFFFFFFFFul, 0xFFFFFFFFFFFFFFFFul, 0xFFFFFFFFFFFFFFFFul },
636
+ };
637
+ assert(!(mask & ~0xFul) && "inbound mask");
638
+ return _mm256_castsi256_pd(_mm256_load_si256((const __m256i*)lut64[mask]));
639
+ }
640
+ template <class T, class A, class = std::enable_if_t<std::is_integral<T>::value>>
641
+ XSIMD_INLINE batch_bool<T, A> from_mask(batch_bool<T, A> const&, uint64_t mask, requires_arch<avx>) noexcept
642
+ {
643
+ XSIMD_IF_CONSTEXPR(sizeof(T) == 1)
644
+ {
645
+ alignas(A::alignment()) static const uint32_t lut32[] = {
646
+ 0x00000000,
647
+ 0x000000FF,
648
+ 0x0000FF00,
649
+ 0x0000FFFF,
650
+ 0x00FF0000,
651
+ 0x00FF00FF,
652
+ 0x00FFFF00,
653
+ 0x00FFFFFF,
654
+ 0xFF000000,
655
+ 0xFF0000FF,
656
+ 0xFF00FF00,
657
+ 0xFF00FFFF,
658
+ 0xFFFF0000,
659
+ 0xFFFF00FF,
660
+ 0xFFFFFF00,
661
+ 0xFFFFFFFF,
662
+ };
663
+ assert(!(mask & ~0xFFFFFFFFul) && "inbound mask");
664
+ return _mm256_setr_epi32(lut32[mask & 0xF], lut32[(mask >> 4) & 0xF],
665
+ lut32[(mask >> 8) & 0xF], lut32[(mask >> 12) & 0xF],
666
+ lut32[(mask >> 16) & 0xF], lut32[(mask >> 20) & 0xF],
667
+ lut32[(mask >> 24) & 0xF], lut32[mask >> 28]);
668
+ }
669
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 2)
670
+ {
671
+ alignas(A::alignment()) static const uint64_t lut64[] = {
672
+ 0x0000000000000000ul,
673
+ 0x000000000000FFFFul,
674
+ 0x00000000FFFF0000ul,
675
+ 0x00000000FFFFFFFFul,
676
+ 0x0000FFFF00000000ul,
677
+ 0x0000FFFF0000FFFFul,
678
+ 0x0000FFFFFFFF0000ul,
679
+ 0x0000FFFFFFFFFFFFul,
680
+ 0xFFFF000000000000ul,
681
+ 0xFFFF00000000FFFFul,
682
+ 0xFFFF0000FFFF0000ul,
683
+ 0xFFFF0000FFFFFFFFul,
684
+ 0xFFFFFFFF00000000ul,
685
+ 0xFFFFFFFF0000FFFFul,
686
+ 0xFFFFFFFFFFFF0000ul,
687
+ 0xFFFFFFFFFFFFFFFFul,
688
+ };
689
+ assert(!(mask & ~0xFFFFul) && "inbound mask");
690
+ return _mm256_setr_epi64x(lut64[mask & 0xF], lut64[(mask >> 4) & 0xF], lut64[(mask >> 8) & 0xF], lut64[(mask >> 12) & 0xF]);
691
+ }
692
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
693
+ {
694
+ return _mm256_castps_si256(from_mask(batch_bool<float, A> {}, mask, avx {}));
695
+ }
696
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 8)
697
+ {
698
+ return _mm256_castpd_si256(from_mask(batch_bool<double, A> {}, mask, avx {}));
699
+ }
700
+ }
701
+
702
+ // haddp
703
+ template <class A>
704
+ XSIMD_INLINE batch<float, A> haddp(batch<float, A> const* row, requires_arch<avx>) noexcept
705
+ {
706
+ // row = (a,b,c,d,e,f,g,h)
707
+ // tmp0 = (a0+a1, a2+a3, b0+b1, b2+b3, a4+a5, a6+a7, b4+b5, b6+b7)
708
+ __m256 tmp0 = _mm256_hadd_ps(row[0], row[1]);
709
+ // tmp1 = (c0+c1, c2+c3, d1+d2, d2+d3, c4+c5, c6+c7, d4+d5, d6+d7)
710
+ __m256 tmp1 = _mm256_hadd_ps(row[2], row[3]);
711
+ // tmp1 = (a0+a1+a2+a3, b0+b1+b2+b3, c0+c1+c2+c3, d0+d1+d2+d3,
712
+ // a4+a5+a6+a7, b4+b5+b6+b7, c4+c5+c6+c7, d4+d5+d6+d7)
713
+ tmp1 = _mm256_hadd_ps(tmp0, tmp1);
714
+ // tmp0 = (e0+e1, e2+e3, f0+f1, f2+f3, e4+e5, e6+e7, f4+f5, f6+f7)
715
+ tmp0 = _mm256_hadd_ps(row[4], row[5]);
716
+ // tmp2 = (g0+g1, g2+g3, h0+h1, h2+h3, g4+g5, g6+g7, h4+h5, h6+h7)
717
+ __m256 tmp2 = _mm256_hadd_ps(row[6], row[7]);
718
+ // tmp2 = (e0+e1+e2+e3, f0+f1+f2+f3, g0+g1+g2+g3, h0+h1+h2+h3,
719
+ // e4+e5+e6+e7, f4+f5+f6+f7, g4+g5+g6+g7, h4+h5+h6+h7)
720
+ tmp2 = _mm256_hadd_ps(tmp0, tmp2);
721
+ // tmp0 = (a0+a1+a2+a3, b0+b1+b2+b3, c0+c1+c2+c3, d0+d1+d2+d3,
722
+ // e4+e5+e6+e7, f4+f5+f6+f7, g4+g5+g6+g7, h4+h5+h6+h7)
723
+ tmp0 = _mm256_blend_ps(tmp1, tmp2, 0b11110000);
724
+ // tmp1 = (a4+a5+a6+a7, b4+b5+b6+b7, c4+c5+c6+c7, d4+d5+d6+d7,
725
+ // e0+e1+e2+e3, f0+f1+f2+f3, g0+g1+g2+g3, h0+h1+h2+h3)
726
+ tmp1 = _mm256_permute2f128_ps(tmp1, tmp2, 0x21);
727
+ return _mm256_add_ps(tmp0, tmp1);
728
+ }
729
+ template <class A>
730
+ XSIMD_INLINE batch<double, A> haddp(batch<double, A> const* row, requires_arch<avx>) noexcept
731
+ {
732
+ // row = (a,b,c,d)
733
+ // tmp0 = (a0+a1, b0+b1, a2+a3, b2+b3)
734
+ __m256d tmp0 = _mm256_hadd_pd(row[0], row[1]);
735
+ // tmp1 = (c0+c1, d0+d1, c2+c3, d2+d3)
736
+ __m256d tmp1 = _mm256_hadd_pd(row[2], row[3]);
737
+ // tmp2 = (a0+a1, b0+b1, c2+c3, d2+d3)
738
+ __m256d tmp2 = _mm256_blend_pd(tmp0, tmp1, 0b1100);
739
+ // tmp1 = (a2+a3, b2+b3, c2+c3, d2+d3)
740
+ tmp1 = _mm256_permute2f128_pd(tmp0, tmp1, 0x21);
741
+ return _mm256_add_pd(tmp1, tmp2);
742
+ }
743
+
744
+ // incr_if
745
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
746
+ XSIMD_INLINE batch<T, A> incr_if(batch<T, A> const& self, batch_bool<T, A> const& mask, requires_arch<avx>) noexcept
747
+ {
748
+ return self - batch<T, A>(mask.data);
749
+ }
750
+
751
+ // first (must precede get for two-phase lookup)
752
+ template <class A>
753
+ XSIMD_INLINE float first(batch<float, A> const& self, requires_arch<avx>) noexcept
754
+ {
755
+ return _mm256_cvtss_f32(self);
756
+ }
757
+
758
+ template <class A>
759
+ XSIMD_INLINE double first(batch<double, A> const& self, requires_arch<avx>) noexcept
760
+ {
761
+ return _mm256_cvtsd_f64(self);
762
+ }
763
+
764
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
765
+ XSIMD_INLINE T first(batch<T, A> const& self, requires_arch<avx>) noexcept
766
+ {
767
+ XSIMD_IF_CONSTEXPR(sizeof(T) == 1)
768
+ {
769
+ return static_cast<T>(_mm_cvtsi128_si32(_mm256_castsi256_si128(self)) & 0xFF);
770
+ }
771
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 2)
772
+ {
773
+ return static_cast<T>(_mm_cvtsi128_si32(_mm256_castsi256_si128(self)) & 0xFFFF);
774
+ }
775
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
776
+ {
777
+ return static_cast<T>(_mm_cvtsi128_si32(_mm256_castsi256_si128(self)));
778
+ }
779
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 8)
780
+ {
781
+ batch<T, sse4_2> low = _mm256_castsi256_si128(self);
782
+ return first(low, sse4_2 {});
783
+ }
784
+ else
785
+ {
786
+ assert(false && "unsupported arch/op combination");
787
+ return {};
788
+ }
789
+ }
790
+
791
+ // get
792
+ template <class A, size_t I>
793
+ XSIMD_INLINE float get(batch<float, A> const& self, ::xsimd::index<I>, requires_arch<avx>) noexcept
794
+ {
795
+ XSIMD_IF_CONSTEXPR(I == 0) { return first(self, avx {}); }
796
+ constexpr size_t elements_per_lane = batch<float, sse4_1>::size;
797
+ constexpr size_t lane = I / elements_per_lane;
798
+ constexpr size_t sub_index = I % elements_per_lane;
799
+ const auto half = (lane == 0) ? detail::lower_half(self) : detail::upper_half(self);
800
+ return kernel::get(batch<float, sse4_1>(half), ::xsimd::index<sub_index> {}, sse4_1 {});
801
+ }
802
+
803
+ template <class A, size_t I>
804
+ XSIMD_INLINE double get(batch<double, A> const& self, ::xsimd::index<I>, requires_arch<avx>) noexcept
805
+ {
806
+ XSIMD_IF_CONSTEXPR(I == 0) { return first(self, avx {}); }
807
+ constexpr size_t elements_per_lane = batch<double, sse4_1>::size;
808
+ constexpr size_t lane = I / elements_per_lane;
809
+ constexpr size_t sub_index = I % elements_per_lane;
810
+ const auto half = (lane == 0) ? detail::lower_half(self) : detail::upper_half(self);
811
+ return kernel::get(batch<double, sse4_1>(half), ::xsimd::index<sub_index> {}, sse4_1 {});
812
+ }
813
+
814
+ template <class A, size_t I, class T, class = std::enable_if_t<std::is_integral<T>::value>>
815
+ XSIMD_INLINE T get(batch<T, A> const& self, ::xsimd::index<I>, requires_arch<avx>) noexcept
816
+ {
817
+ XSIMD_IF_CONSTEXPR(I == 0) { return first(self, avx {}); }
818
+ constexpr size_t elements_per_lane = batch<T, sse4_1>::size;
819
+ constexpr size_t lane = I / elements_per_lane;
820
+ constexpr size_t sub_index = I % elements_per_lane;
821
+ const auto half = (lane == 0) ? detail::lower_half(self) : detail::upper_half(self);
822
+ return kernel::get(batch<T, sse4_1>(half), ::xsimd::index<sub_index> {}, sse4_1 {});
823
+ }
824
+
825
+ // insert
826
+ template <class A, class T, size_t I, class = std::enable_if_t<std::is_integral<T>::value>>
827
+ XSIMD_INLINE batch<T, A> insert(batch<T, A> const& self, T val, index<I> pos, requires_arch<avx>) noexcept
828
+ {
829
+ #if !defined(_MSC_VER) || _MSC_VER > 1900
830
+ XSIMD_IF_CONSTEXPR(sizeof(T) == 1)
831
+ {
832
+ return _mm256_insert_epi8(self, val, I);
833
+ }
834
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 2)
835
+ {
836
+ return _mm256_insert_epi16(self, val, I);
837
+ }
838
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
839
+ {
840
+ return _mm256_insert_epi32(self, val, I);
841
+ }
842
+ else
843
+ {
844
+ return insert(self, val, pos, common {});
845
+ }
846
+ #endif
847
+ return insert(self, val, pos, common {});
848
+ }
849
+
850
+ // isnan
851
+ template <class A>
852
+ XSIMD_INLINE batch_bool<float, A> isnan(batch<float, A> const& self, requires_arch<avx>) noexcept
853
+ {
854
+ return _mm256_cmp_ps(self, self, _CMP_UNORD_Q);
855
+ }
856
+ template <class A>
857
+ XSIMD_INLINE batch_bool<double, A> isnan(batch<double, A> const& self, requires_arch<avx>) noexcept
858
+ {
859
+ return _mm256_cmp_pd(self, self, _CMP_UNORD_Q);
860
+ }
861
+
862
+ // le
863
+ template <class A>
864
+ XSIMD_INLINE batch_bool<float, A> le(batch<float, A> const& self, batch<float, A> const& other, requires_arch<avx>) noexcept
865
+ {
866
+ return _mm256_cmp_ps(self, other, _CMP_LE_OQ);
867
+ }
868
+ template <class A>
869
+ XSIMD_INLINE batch_bool<double, A> le(batch<double, A> const& self, batch<double, A> const& other, requires_arch<avx>) noexcept
870
+ {
871
+ return _mm256_cmp_pd(self, other, _CMP_LE_OQ);
872
+ }
873
+
874
+ // load_aligned
875
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
876
+ XSIMD_INLINE batch<T, A> load_aligned(T const* mem, convert<T>, requires_arch<avx>) noexcept
877
+ {
878
+ return _mm256_load_si256((__m256i const*)mem);
879
+ }
880
+ template <class A>
881
+ XSIMD_INLINE batch<float, A> load_aligned(float const* mem, convert<float>, requires_arch<avx>) noexcept
882
+ {
883
+ return _mm256_load_ps(mem);
884
+ }
885
+ template <class A>
886
+ XSIMD_INLINE batch<double, A> load_aligned(double const* mem, convert<double>, requires_arch<avx>) noexcept
887
+ {
888
+ return _mm256_load_pd(mem);
889
+ }
890
+
891
+ namespace detail
892
+ {
893
+ // load_complex
894
+ template <class A>
895
+ XSIMD_INLINE batch<std::complex<float>, A> load_complex(batch<float, A> const& hi, batch<float, A> const& lo, requires_arch<avx>) noexcept
896
+ {
897
+ using batch_type = batch<float, A>;
898
+ __m128 tmp0 = _mm256_extractf128_ps(hi, 0);
899
+ __m128 tmp1 = _mm256_extractf128_ps(hi, 1);
900
+ __m128 tmp_real = _mm_shuffle_ps(tmp0, tmp1, _MM_SHUFFLE(2, 0, 2, 0));
901
+ __m128 tmp_imag = _mm_shuffle_ps(tmp0, tmp1, _MM_SHUFFLE(3, 1, 3, 1));
902
+ batch_type real = _mm256_castps128_ps256(tmp_real);
903
+ batch_type imag = _mm256_castps128_ps256(tmp_imag);
904
+
905
+ tmp0 = _mm256_extractf128_ps(lo, 0);
906
+ tmp1 = _mm256_extractf128_ps(lo, 1);
907
+ tmp_real = _mm_shuffle_ps(tmp0, tmp1, _MM_SHUFFLE(2, 0, 2, 0));
908
+ tmp_imag = _mm_shuffle_ps(tmp0, tmp1, _MM_SHUFFLE(3, 1, 3, 1));
909
+ real = _mm256_insertf128_ps(real, tmp_real, 1);
910
+ imag = _mm256_insertf128_ps(imag, tmp_imag, 1);
911
+ return { real, imag };
912
+ }
913
+ template <class A>
914
+ XSIMD_INLINE batch<std::complex<double>, A> load_complex(batch<double, A> const& hi, batch<double, A> const& lo, requires_arch<avx>) noexcept
915
+ {
916
+ using batch_type = batch<double, A>;
917
+ __m128d tmp0 = _mm256_extractf128_pd(hi, 0);
918
+ __m128d tmp1 = _mm256_extractf128_pd(hi, 1);
919
+ batch_type real = _mm256_castpd128_pd256(_mm_unpacklo_pd(tmp0, tmp1));
920
+ batch_type imag = _mm256_castpd128_pd256(_mm_unpackhi_pd(tmp0, tmp1));
921
+
922
+ tmp0 = _mm256_extractf128_pd(lo, 0);
923
+ tmp1 = _mm256_extractf128_pd(lo, 1);
924
+ __m256d re_tmp1 = _mm256_insertf128_pd(real, _mm_unpacklo_pd(tmp0, tmp1), 1);
925
+ __m256d im_tmp1 = _mm256_insertf128_pd(imag, _mm_unpackhi_pd(tmp0, tmp1), 1);
926
+ real = _mm256_blend_pd(real, re_tmp1, 12);
927
+ imag = _mm256_blend_pd(imag, im_tmp1, 12);
928
+ return { real, imag };
929
+ }
930
+ }
931
+
932
+ // load_unaligned
933
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
934
+ XSIMD_INLINE batch<T, A> load_unaligned(T const* mem, convert<T>, requires_arch<avx>) noexcept
935
+ {
936
+ return _mm256_loadu_si256((__m256i const*)mem);
937
+ }
938
+ template <class A>
939
+ XSIMD_INLINE batch<float, A> load_unaligned(float const* mem, convert<float>, requires_arch<avx>) noexcept
940
+ {
941
+ return _mm256_loadu_ps(mem);
942
+ }
943
+ template <class A>
944
+ XSIMD_INLINE batch<double, A> load_unaligned(double const* mem, convert<double>, requires_arch<avx>) noexcept
945
+ {
946
+ return _mm256_loadu_pd(mem);
947
+ }
948
+
949
+ // AVX helpers to avoid type-based branching in the generic load_masked
950
+ namespace detail
951
+ {
952
+ template <class A>
953
+ XSIMD_INLINE batch<float, A> maskload(float const* mem, batch<as_integer_t<float>, A> const& mask) noexcept
954
+ {
955
+ return _mm256_maskload_ps(mem, mask);
956
+ }
957
+
958
+ template <class A>
959
+ XSIMD_INLINE batch<double, A> maskload(double const* mem, batch<as_integer_t<double>, A> const& mask) noexcept
960
+ {
961
+ return _mm256_maskload_pd(mem, mask);
962
+ }
963
+
964
+ template <class A>
965
+ XSIMD_INLINE batch<float, A> zero_extend(batch<float, A> const& hi) noexcept
966
+ {
967
+ return _mm256_insertf128_ps(_mm256_setzero_ps(), hi, 1);
968
+ }
969
+
970
+ template <class A>
971
+ XSIMD_INLINE batch<double, A> zero_extend(batch<double, A> const& hi) noexcept
972
+ {
973
+ return _mm256_insertf128_pd(_mm256_setzero_pd(), hi, 1);
974
+ }
975
+
976
+ // allow inserting a 128-bit SSE batch into the upper half of an AVX batch
977
+ template <class A, class SrcA>
978
+ XSIMD_INLINE batch<float, A> zero_extend(batch<float, SrcA> const& hi) noexcept
979
+ {
980
+ return _mm256_insertf128_ps(_mm256_setzero_ps(), hi, 1);
981
+ }
982
+
983
+ template <class A, class SrcA>
984
+ XSIMD_INLINE batch<double, A> zero_extend(batch<double, SrcA> const& hi) noexcept
985
+ {
986
+ return _mm256_insertf128_pd(_mm256_setzero_pd(), hi, 1);
987
+ }
988
+ }
989
+
990
+ // load_masked (single overload for float/double)
991
+ template <class A, class T, bool... Values, class Mode, class = std::enable_if_t<std::is_floating_point<T>::value>>
992
+ XSIMD_INLINE batch<T, A> load_masked(T const* mem, batch_bool_constant<T, A, Values...> mask, convert<T>, Mode, requires_arch<avx>) noexcept
993
+ {
994
+ using int_t = as_integer_t<T>;
995
+ constexpr size_t half_size = batch<T, A>::size / 2;
996
+
997
+ // confined to lower 128-bit half → forward to 128 bit
998
+ XSIMD_IF_CONSTEXPR(mask.countl_zero() >= half_size)
999
+ {
1000
+ constexpr auto mlo = ::xsimd::detail::lower_half<sse4_2>(batch_bool_constant<int_t, A, Values...> {});
1001
+ const auto lo = load_masked(reinterpret_cast<int_t const*>(mem), mlo, convert<int_t> {}, Mode {}, avx_128 {});
1002
+ return bitwise_cast<T>(batch<int_t, A>(_mm256_zextsi128_si256(lo)));
1003
+ }
1004
+ // confined to upper 128-bit half → forward to 128 bit
1005
+ else XSIMD_IF_CONSTEXPR(mask.countr_zero() >= half_size)
1006
+ {
1007
+ constexpr auto mhi = ::xsimd::detail::upper_half<sse4_2>(mask);
1008
+ const auto hi = load_masked(mem + half_size, mhi, convert<T> {}, Mode {}, avx_128 {});
1009
+ return detail::zero_extend<A>(hi);
1010
+ }
1011
+ else
1012
+ {
1013
+ // crossing 128-bit boundary → use 256-bit masked load
1014
+ return detail::maskload<A>(mem, mask.as_batch());
1015
+ }
1016
+ }
1017
+
1018
+ // store_masked
1019
+ namespace detail
1020
+ {
1021
+ template <class A>
1022
+ XSIMD_INLINE void maskstore(float* mem, batch_bool<float, A> const& mask, batch<float, A> const& src) noexcept
1023
+ {
1024
+ _mm256_maskstore_ps(mem, mask, src);
1025
+ }
1026
+
1027
+ template <class A>
1028
+ XSIMD_INLINE void maskstore(double* mem, batch_bool<double, A> const& mask, batch<double, A> const& src) noexcept
1029
+ {
1030
+ _mm256_maskstore_pd(mem, mask, src);
1031
+ }
1032
+ }
1033
+
1034
+ template <class A, class T, bool... Values, class Mode>
1035
+ XSIMD_INLINE void store_masked(T* mem, batch<T, A> const& src, batch_bool_constant<T, A, Values...> mask, Mode, requires_arch<avx>) noexcept
1036
+ {
1037
+ constexpr size_t half_size = batch<T, A>::size / 2;
1038
+
1039
+ // confined to lower 128-bit half → forward to 128 bit
1040
+ XSIMD_IF_CONSTEXPR(mask.countl_zero() >= half_size)
1041
+ {
1042
+ constexpr auto mlo = ::xsimd::detail::lower_half<sse4_2>(mask);
1043
+ const auto lo = detail::lower_half(src);
1044
+ store_masked<avx_128>(mem, lo, mlo, Mode {}, sse4_2 {});
1045
+ }
1046
+ // confined to upper 128-bit half → forward to 128 bit
1047
+ else XSIMD_IF_CONSTEXPR(mask.countr_zero() >= half_size)
1048
+ {
1049
+ constexpr auto mhi = ::xsimd::detail::upper_half<sse4_2>(mask);
1050
+ const auto hi = detail::upper_half(src);
1051
+ store_masked<avx_128>(mem + half_size, hi, mhi, Mode {}, sse4_2 {});
1052
+ }
1053
+ else
1054
+ {
1055
+ detail::maskstore(mem, mask.as_batch(), src);
1056
+ }
1057
+ }
1058
+
1059
+ // lt
1060
+ template <class A>
1061
+ XSIMD_INLINE batch_bool<float, A> lt(batch<float, A> const& self, batch<float, A> const& other, requires_arch<avx>) noexcept
1062
+ {
1063
+ return _mm256_cmp_ps(self, other, _CMP_LT_OQ);
1064
+ }
1065
+ template <class A>
1066
+ XSIMD_INLINE batch_bool<double, A> lt(batch<double, A> const& self, batch<double, A> const& other, requires_arch<avx>) noexcept
1067
+ {
1068
+ return _mm256_cmp_pd(self, other, _CMP_LT_OQ);
1069
+ }
1070
+
1071
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
1072
+ XSIMD_INLINE batch_bool<T, A> lt(batch<T, A> const& self, batch<T, A> const& other, requires_arch<avx>) noexcept
1073
+ {
1074
+ return detail::fwd_to_sse([](__m128i s, __m128i o) noexcept
1075
+ { return lt(batch<T, sse4_2>(s), batch<T, sse4_2>(o)); },
1076
+ self, other);
1077
+ }
1078
+
1079
+ // mask
1080
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
1081
+ XSIMD_INLINE uint64_t mask(batch_bool<T, A> const& self, requires_arch<avx>) noexcept
1082
+ {
1083
+ XSIMD_IF_CONSTEXPR(sizeof(T) == 1 || sizeof(T) == 2)
1084
+ {
1085
+ __m128i self_low = detail::lower_half(self), self_high = detail::upper_half(self);
1086
+ return mask(batch_bool<T, sse4_2>(self_low), sse4_2 {}) | (mask(batch_bool<T, sse4_2>(self_high), sse4_2 {}) << (128 / (8 * sizeof(T))));
1087
+ }
1088
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
1089
+ {
1090
+ return _mm256_movemask_ps(_mm256_castsi256_ps(self));
1091
+ }
1092
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 8)
1093
+ {
1094
+ return _mm256_movemask_pd(_mm256_castsi256_pd(self));
1095
+ }
1096
+ else
1097
+ {
1098
+ assert(false && "unsupported arch/op combination");
1099
+ return {};
1100
+ }
1101
+ }
1102
+ template <class A>
1103
+ XSIMD_INLINE uint64_t mask(batch_bool<float, A> const& self, requires_arch<avx>) noexcept
1104
+ {
1105
+ return _mm256_movemask_ps(self);
1106
+ }
1107
+
1108
+ template <class A>
1109
+ XSIMD_INLINE uint64_t mask(batch_bool<double, A> const& self, requires_arch<avx>) noexcept
1110
+ {
1111
+ return _mm256_movemask_pd(self);
1112
+ }
1113
+
1114
+ // max
1115
+ template <class A>
1116
+ XSIMD_INLINE batch<float, A> max(batch<float, A> const& self, batch<float, A> const& other, requires_arch<avx>) noexcept
1117
+ {
1118
+ return _mm256_max_ps(other, self);
1119
+ }
1120
+ template <class A>
1121
+ XSIMD_INLINE batch<double, A> max(batch<double, A> const& self, batch<double, A> const& other, requires_arch<avx>) noexcept
1122
+ {
1123
+ return _mm256_max_pd(other, self);
1124
+ }
1125
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
1126
+ XSIMD_INLINE batch<T, A> max(batch<T, A> const& self, batch<T, A> const& other, requires_arch<avx>) noexcept
1127
+ {
1128
+ return select(self > other, self, other);
1129
+ }
1130
+
1131
+ // min
1132
+ template <class A>
1133
+ XSIMD_INLINE batch<float, A> min(batch<float, A> const& self, batch<float, A> const& other, requires_arch<avx>) noexcept
1134
+ {
1135
+ return _mm256_min_ps(other, self);
1136
+ }
1137
+ template <class A>
1138
+ XSIMD_INLINE batch<double, A> min(batch<double, A> const& self, batch<double, A> const& other, requires_arch<avx>) noexcept
1139
+ {
1140
+ return _mm256_min_pd(other, self);
1141
+ }
1142
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
1143
+ XSIMD_INLINE batch<T, A> min(batch<T, A> const& self, batch<T, A> const& other, requires_arch<avx>) noexcept
1144
+ {
1145
+ return select(self <= other, self, other);
1146
+ }
1147
+
1148
+ // mul
1149
+ template <class A>
1150
+ XSIMD_INLINE batch<float, A> mul(batch<float, A> const& self, batch<float, A> const& other, requires_arch<avx>) noexcept
1151
+ {
1152
+ return _mm256_mul_ps(self, other);
1153
+ }
1154
+ template <class A>
1155
+ XSIMD_INLINE batch<double, A> mul(batch<double, A> const& self, batch<double, A> const& other, requires_arch<avx>) noexcept
1156
+ {
1157
+ return _mm256_mul_pd(self, other);
1158
+ }
1159
+
1160
+ // nearbyint
1161
+ template <class A>
1162
+ XSIMD_INLINE batch<float, A> nearbyint(batch<float, A> const& self, requires_arch<avx>) noexcept
1163
+ {
1164
+ return _mm256_round_ps(self, _MM_FROUND_TO_NEAREST_INT);
1165
+ }
1166
+ template <class A>
1167
+ XSIMD_INLINE batch<double, A> nearbyint(batch<double, A> const& self, requires_arch<avx>) noexcept
1168
+ {
1169
+ return _mm256_round_pd(self, _MM_FROUND_TO_NEAREST_INT);
1170
+ }
1171
+
1172
+ // nearbyint_as_int
1173
+ template <class A>
1174
+ XSIMD_INLINE batch<int32_t, A> nearbyint_as_int(batch<float, A> const& self,
1175
+ requires_arch<avx>) noexcept
1176
+ {
1177
+ return _mm256_cvtps_epi32(self);
1178
+ }
1179
+
1180
+ // neg
1181
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
1182
+ XSIMD_INLINE batch<T, A> neg(batch<T, A> const& self, requires_arch<avx>) noexcept
1183
+ {
1184
+ return 0 - self;
1185
+ }
1186
+ template <class A>
1187
+ batch<float, A> neg(batch<float, A> const& self, requires_arch<avx>)
1188
+ {
1189
+ return _mm256_xor_ps(self, _mm256_castsi256_ps(_mm256_set1_epi32(0x80000000)));
1190
+ }
1191
+ template <class A>
1192
+ XSIMD_INLINE batch<double, A> neg(batch<double, A> const& self, requires_arch<avx>) noexcept
1193
+ {
1194
+ return _mm256_xor_pd(self, _mm256_castsi256_pd(_mm256_set1_epi64x(0x8000000000000000)));
1195
+ }
1196
+
1197
+ // neq
1198
+ template <class A>
1199
+ XSIMD_INLINE batch_bool<float, A> neq(batch<float, A> const& self, batch<float, A> const& other, requires_arch<avx>) noexcept
1200
+ {
1201
+ return _mm256_cmp_ps(self, other, _CMP_NEQ_UQ);
1202
+ }
1203
+ template <class A>
1204
+ XSIMD_INLINE batch_bool<double, A> neq(batch<double, A> const& self, batch<double, A> const& other, requires_arch<avx>) noexcept
1205
+ {
1206
+ return _mm256_cmp_pd(self, other, _CMP_NEQ_UQ);
1207
+ }
1208
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
1209
+ XSIMD_INLINE batch_bool<T, A> neq(batch<T, A> const& self, batch<T, A> const& other, requires_arch<avx>) noexcept
1210
+ {
1211
+ return ~(self == other);
1212
+ }
1213
+
1214
+ template <class A>
1215
+ XSIMD_INLINE batch_bool<float, A> neq(batch_bool<float, A> const& self, batch_bool<float, A> const& other, requires_arch<avx>) noexcept
1216
+ {
1217
+ return _mm256_xor_ps(self, other);
1218
+ }
1219
+ template <class A>
1220
+ XSIMD_INLINE batch_bool<double, A> neq(batch_bool<double, A> const& self, batch_bool<double, A> const& other, requires_arch<avx>) noexcept
1221
+ {
1222
+ return _mm256_xor_pd(self, other);
1223
+ }
1224
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
1225
+ XSIMD_INLINE batch_bool<T, A> neq(batch_bool<T, A> const& self, batch_bool<T, A> const& other, requires_arch<avx>) noexcept
1226
+ {
1227
+ return _mm256_castps_si256(_mm256_xor_ps(_mm256_castsi256_ps(self.data), _mm256_castsi256_ps(other.data)));
1228
+ }
1229
+
1230
+ // reciprocal
1231
+ template <class A>
1232
+ XSIMD_INLINE batch<float, A> reciprocal(batch<float, A> const& self,
1233
+ kernel::requires_arch<avx>) noexcept
1234
+ {
1235
+ return _mm256_rcp_ps(self);
1236
+ }
1237
+
1238
+ // reduce_add
1239
+ template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
1240
+ XSIMD_INLINE T reduce_add(batch<T, A> const& self, requires_arch<avx>) noexcept
1241
+ {
1242
+ typename batch<T, sse4_2>::register_type low = detail::lower_half(self), high = detail::upper_half(self);
1243
+ batch<T, sse4_2> blow(low), bhigh(high);
1244
+ return reduce_add(blow + bhigh);
1245
+ }
1246
+
1247
+ // reduce_max
1248
+ template <class A, class T, class = std::enable_if_t<(sizeof(T) <= 2)>>
1249
+ XSIMD_INLINE T reduce_max(batch<T, A> const& self, requires_arch<avx>) noexcept
1250
+ {
1251
+ constexpr auto mask = detail::shuffle(1, 0);
1252
+ batch<T, A> step = _mm256_permute2f128_si256(self, self, mask);
1253
+ batch<T, A> acc = max(self, step);
1254
+ __m128i low = _mm256_castsi256_si128(acc);
1255
+ return reduce_max(batch<T, sse4_2>(low));
1256
+ }
1257
+
1258
+ // reduce_min
1259
+ template <class A, class T, class = std::enable_if_t<(sizeof(T) <= 2)>>
1260
+ XSIMD_INLINE T reduce_min(batch<T, A> const& self, requires_arch<avx>) noexcept
1261
+ {
1262
+ constexpr auto mask = detail::shuffle(1, 0);
1263
+ batch<T, A> step = _mm256_permute2f128_si256(self, self, mask);
1264
+ batch<T, A> acc = min(self, step);
1265
+ __m128i low = _mm256_castsi256_si128(acc);
1266
+ return reduce_min(batch<T, sse4_2>(low));
1267
+ }
1268
+
1269
+ // reduce_mul
1270
+ template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
1271
+ XSIMD_INLINE T reduce_mul(batch<T, A> const& self, requires_arch<avx>) noexcept
1272
+ {
1273
+ typename batch<T, sse4_2>::register_type low = detail::lower_half(self), high = detail::upper_half(self);
1274
+ batch<T, sse4_2> blow(low), bhigh(high);
1275
+ return reduce_mul(blow * bhigh);
1276
+ }
1277
+
1278
+ // rsqrt
1279
+ template <class A>
1280
+ XSIMD_INLINE batch<float, A> rsqrt(batch<float, A> const& val, requires_arch<avx>) noexcept
1281
+ {
1282
+ return _mm256_rsqrt_ps(val);
1283
+ }
1284
+ template <class A>
1285
+ XSIMD_INLINE batch<double, A> rsqrt(batch<double, A> const& val, requires_arch<avx>) noexcept
1286
+ {
1287
+ return _mm256_cvtps_pd(_mm_rsqrt_ps(_mm256_cvtpd_ps(val)));
1288
+ }
1289
+
1290
+ // sadd
1291
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
1292
+ XSIMD_INLINE batch<T, A> sadd(batch<T, A> const& self, batch<T, A> const& other, requires_arch<avx>) noexcept
1293
+ {
1294
+ if (std::is_signed<T>::value)
1295
+ {
1296
+ auto mask = (other >> (8 * sizeof(T) - 1));
1297
+ auto self_pos_branch = min(std::numeric_limits<T>::max() - other, self);
1298
+ auto self_neg_branch = max(std::numeric_limits<T>::min() - other, self);
1299
+ return other + select(batch_bool<T, A>(mask.data), self_neg_branch, self_pos_branch);
1300
+ }
1301
+ else
1302
+ {
1303
+ const auto diffmax = std::numeric_limits<T>::max() - self;
1304
+ const auto mindiff = min(diffmax, other);
1305
+ return self + mindiff;
1306
+ }
1307
+ }
1308
+
1309
+ // select
1310
+ template <class A>
1311
+ 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<avx>) noexcept
1312
+ {
1313
+ return _mm256_blendv_ps(false_br, true_br, cond);
1314
+ }
1315
+ template <class A>
1316
+ 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<avx>) noexcept
1317
+ {
1318
+ return _mm256_blendv_pd(false_br, true_br, cond);
1319
+ }
1320
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
1321
+ 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<avx>) noexcept
1322
+ {
1323
+ __m128i cond_low = detail::lower_half(cond), cond_hi = detail::upper_half(cond);
1324
+
1325
+ __m128i true_low = detail::lower_half(true_br), true_hi = detail::upper_half(true_br);
1326
+
1327
+ __m128i false_low = detail::lower_half(false_br), false_hi = detail::upper_half(false_br);
1328
+
1329
+ __m128i res_low = select(batch_bool<T, sse4_2>(cond_low), batch<T, sse4_2>(true_low), batch<T, sse4_2>(false_low), sse4_2 {});
1330
+ __m128i res_hi = select(batch_bool<T, sse4_2>(cond_hi), batch<T, sse4_2>(true_hi), batch<T, sse4_2>(false_hi), sse4_2 {});
1331
+ return detail::merge_sse(res_low, res_hi);
1332
+ }
1333
+ template <class A, class T, bool... Values, class = std::enable_if_t<std::is_integral<T>::value>>
1334
+ 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<avx>) noexcept
1335
+ {
1336
+ return select(batch_bool<T, A> { Values... }, true_br, false_br, avx2 {});
1337
+ }
1338
+
1339
+ template <class A, bool... Values>
1340
+ XSIMD_INLINE batch<float, A> select(batch_bool_constant<float, A, Values...> const&, batch<float, A> const& true_br, batch<float, A> const& false_br, requires_arch<avx>) noexcept
1341
+ {
1342
+ constexpr auto mask = batch_bool_constant<float, A, Values...>::mask();
1343
+ return _mm256_blend_ps(false_br, true_br, mask);
1344
+ }
1345
+
1346
+ template <class A, bool... Values>
1347
+ XSIMD_INLINE batch<double, A> select(batch_bool_constant<double, A, Values...> const&, batch<double, A> const& true_br, batch<double, A> const& false_br, requires_arch<avx>) noexcept
1348
+ {
1349
+ constexpr auto mask = batch_bool_constant<double, A, Values...>::mask();
1350
+ return _mm256_blend_pd(false_br, true_br, mask);
1351
+ }
1352
+
1353
+ // set
1354
+ template <class A, class... Values>
1355
+ XSIMD_INLINE batch<float, A> set(batch<float, A> const&, requires_arch<avx>, Values... values) noexcept
1356
+ {
1357
+ static_assert(sizeof...(Values) == batch<float, A>::size, "consistent init");
1358
+ return _mm256_setr_ps(values...);
1359
+ }
1360
+
1361
+ template <class A, class... Values>
1362
+ XSIMD_INLINE batch<double, A> set(batch<double, A> const&, requires_arch<avx>, Values... values) noexcept
1363
+ {
1364
+ static_assert(sizeof...(Values) == batch<double, A>::size, "consistent init");
1365
+ return _mm256_setr_pd(values...);
1366
+ }
1367
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
1368
+ XSIMD_INLINE batch<T, A> set(batch<T, A> const&, requires_arch<avx>, T v0, T v1, T v2, T v3) noexcept
1369
+ {
1370
+ return _mm256_set_epi64x(v3, v2, v1, v0);
1371
+ }
1372
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
1373
+ XSIMD_INLINE batch<T, A> set(batch<T, A> const&, requires_arch<avx>, T v0, T v1, T v2, T v3, T v4, T v5, T v6, T v7) noexcept
1374
+ {
1375
+ return _mm256_setr_epi32(v0, v1, v2, v3, v4, v5, v6, v7);
1376
+ }
1377
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
1378
+ XSIMD_INLINE batch<T, A> set(batch<T, A> const&, requires_arch<avx>, T v0, T v1, T v2, T v3, T v4, T v5, T v6, T v7, T v8, T v9, T v10, T v11, T v12, T v13, T v14, T v15) noexcept
1379
+ {
1380
+ return _mm256_setr_epi16(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15);
1381
+ }
1382
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
1383
+ XSIMD_INLINE batch<T, A> set(batch<T, A> const&, requires_arch<avx>, T v0, T v1, T v2, T v3, T v4, T v5, T v6, T v7, T v8, T v9, T v10, T v11, T v12, T v13, T v14, T v15,
1384
+ T v16, T v17, T v18, T v19, T v20, T v21, T v22, T v23, T v24, T v25, T v26, T v27, T v28, T v29, T v30, T v31) noexcept
1385
+ {
1386
+ return _mm256_setr_epi8(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31);
1387
+ }
1388
+
1389
+ template <class A, class T, class... Values, class = std::enable_if_t<std::is_integral<T>::value>>
1390
+ XSIMD_INLINE batch_bool<T, A> set(batch_bool<T, A> const&, requires_arch<avx>, Values... values) noexcept
1391
+ {
1392
+ return set(batch<T, A>(), A {}, static_cast<T>(values ? -1LL : 0LL)...).data;
1393
+ }
1394
+
1395
+ template <class A, class... Values>
1396
+ XSIMD_INLINE batch_bool<float, A> set(batch_bool<float, A> const&, requires_arch<avx>, Values... values) noexcept
1397
+ {
1398
+ static_assert(sizeof...(Values) == batch_bool<float, A>::size, "consistent init");
1399
+ return _mm256_castsi256_ps(set(batch<int32_t, A>(), A {}, static_cast<int32_t>(values ? -1LL : 0LL)...).data);
1400
+ }
1401
+
1402
+ template <class A, class... Values>
1403
+ XSIMD_INLINE batch_bool<double, A> set(batch_bool<double, A> const&, requires_arch<avx>, Values... values) noexcept
1404
+ {
1405
+ static_assert(sizeof...(Values) == batch_bool<double, A>::size, "consistent init");
1406
+ return _mm256_castsi256_pd(set(batch<int64_t, A>(), A {}, static_cast<int64_t>(values ? -1LL : 0LL)...).data);
1407
+ }
1408
+
1409
+ // shuffle
1410
+ template <class A, class ITy, ITy I0, ITy I1, ITy I2, ITy I3, ITy I4, ITy I5, ITy I6, ITy I7>
1411
+ XSIMD_INLINE batch<float, A> shuffle(batch<float, A> const& x, batch<float, A> const& y, batch_constant<ITy, A, I0, I1, I2, I3, I4, I5, I6, I7> mask, requires_arch<avx>) noexcept
1412
+ {
1413
+ constexpr uint32_t smask = detail::mod_shuffle(I0, I1, I2, I3);
1414
+ // shuffle within lane
1415
+ if (I4 == (I0 + 4) && I5 == (I1 + 4) && I6 == (I2 + 4) && I7 == (I3 + 4) && I0 < 4 && I1 < 4 && I2 >= 8 && I2 < 12 && I3 >= 8 && I3 < 12)
1416
+ return _mm256_shuffle_ps(x, y, smask);
1417
+
1418
+ // shuffle within opposite lane
1419
+ if (I4 == (I0 + 4) && I5 == (I1 + 4) && I6 == (I2 + 4) && I7 == (I3 + 4) && I2 < 4 && I3 < 4 && I0 >= 8 && I0 < 12 && I1 >= 8 && I1 < 12)
1420
+ return _mm256_shuffle_ps(y, x, smask);
1421
+
1422
+ return shuffle(x, y, mask, common {});
1423
+ }
1424
+
1425
+ template <class A, class ITy, ITy I0, ITy I1, ITy I2, ITy I3>
1426
+ XSIMD_INLINE batch<double, A> shuffle(batch<double, A> const& x, batch<double, A> const& y, batch_constant<ITy, A, I0, I1, I2, I3> mask, requires_arch<avx>) noexcept
1427
+ {
1428
+ constexpr uint32_t smask = (I0 & 0x1) | ((I1 & 0x1) << 1) | ((I2 & 0x1) << 2) | ((I3 & 0x1) << 3);
1429
+ // shuffle within lane
1430
+ if (I0 < 2 && I1 >= 4 && I1 < 6 && I2 >= 2 && I2 < 4 && I3 >= 6)
1431
+ return _mm256_shuffle_pd(x, y, smask);
1432
+
1433
+ // shuffle within opposite lane
1434
+ if (I1 < 2 && I0 >= 4 && I0 < 6 && I3 >= 2 && I3 < 4 && I2 >= 6)
1435
+ return _mm256_shuffle_pd(y, x, smask);
1436
+
1437
+ return shuffle(x, y, mask, common {});
1438
+ }
1439
+
1440
+ // slide_left
1441
+ template <size_t N, class A, class T>
1442
+ XSIMD_INLINE batch<T, A> slide_left(batch<T, A> const& x, requires_arch<avx>) noexcept
1443
+ {
1444
+ constexpr unsigned BitCount = N * 8;
1445
+ if (BitCount == 0)
1446
+ {
1447
+ return x;
1448
+ }
1449
+ if (BitCount >= 256)
1450
+ {
1451
+ return batch<T, A>(T(0));
1452
+ }
1453
+ if (BitCount > 128)
1454
+ {
1455
+ constexpr unsigned M = (BitCount - 128) / 8;
1456
+ __m128i low = _mm256_castsi256_si128(x);
1457
+ auto y = _mm_slli_si128(low, M);
1458
+ __m256i zero = _mm256_setzero_si256();
1459
+ return _mm256_insertf128_si256(zero, y, 1);
1460
+ }
1461
+ if (BitCount == 128)
1462
+ {
1463
+ __m128i low = _mm256_castsi256_si128(x);
1464
+ __m256i zero = _mm256_setzero_si256();
1465
+ return _mm256_insertf128_si256(zero, low, 1);
1466
+ }
1467
+ // shifting by [0, 128[ bits
1468
+ constexpr unsigned M = BitCount / 8;
1469
+
1470
+ __m128i low = _mm256_castsi256_si128(x);
1471
+ auto ylow = _mm_slli_si128(low, M);
1472
+ auto zlow = _mm_srli_si128(low, 16 - M);
1473
+
1474
+ __m128i high = _mm256_extractf128_si256(x, 1);
1475
+ auto yhigh = _mm_slli_si128(high, M);
1476
+
1477
+ __m256i res = _mm256_castsi128_si256(ylow);
1478
+ return _mm256_insertf128_si256(res, _mm_or_si128(yhigh, zlow), 1);
1479
+ }
1480
+
1481
+ // slide_right
1482
+ template <size_t N, class A, class T>
1483
+ XSIMD_INLINE batch<T, A> slide_right(batch<T, A> const& x, requires_arch<avx>) noexcept
1484
+ {
1485
+ constexpr unsigned BitCount = N * 8;
1486
+ if (BitCount == 0)
1487
+ {
1488
+ return x;
1489
+ }
1490
+ if (BitCount >= 256)
1491
+ {
1492
+ return batch<T, A>(T(0));
1493
+ }
1494
+ if (BitCount > 128)
1495
+ {
1496
+ constexpr unsigned M = (BitCount - 128) / 8;
1497
+ __m128i high = _mm256_extractf128_si256(x, 1);
1498
+ __m128i y = _mm_srli_si128(high, M);
1499
+ __m256i zero = _mm256_setzero_si256();
1500
+ return _mm256_insertf128_si256(zero, y, 0);
1501
+ }
1502
+ if (BitCount == 128)
1503
+ {
1504
+ __m128i high = _mm256_extractf128_si256(x, 1);
1505
+ return _mm256_castsi128_si256(high);
1506
+ }
1507
+ // shifting by [0, 128[ bits
1508
+ constexpr unsigned M = BitCount / 8;
1509
+
1510
+ __m128i low = _mm256_castsi256_si128(x);
1511
+ auto ylow = _mm_srli_si128(low, M);
1512
+
1513
+ __m128i high = _mm256_extractf128_si256(x, 1);
1514
+ auto yhigh = _mm_srli_si128(high, M);
1515
+ auto zhigh = _mm_slli_si128(high, 16 - M);
1516
+
1517
+ __m256i res = _mm256_castsi128_si256(_mm_or_si128(ylow, zhigh));
1518
+ return _mm256_insertf128_si256(res, yhigh, 1);
1519
+ }
1520
+
1521
+ // sqrt
1522
+ template <class A>
1523
+ XSIMD_INLINE batch<float, A> sqrt(batch<float, A> const& val, requires_arch<avx>) noexcept
1524
+ {
1525
+ return _mm256_sqrt_ps(val);
1526
+ }
1527
+ template <class A>
1528
+ XSIMD_INLINE batch<double, A> sqrt(batch<double, A> const& val, requires_arch<avx>) noexcept
1529
+ {
1530
+ return _mm256_sqrt_pd(val);
1531
+ }
1532
+
1533
+ // ssub
1534
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
1535
+ XSIMD_INLINE batch<T, A> ssub(batch<T, A> const& self, batch<T, A> const& other, requires_arch<avx>) noexcept
1536
+ {
1537
+ if (std::is_signed<T>::value)
1538
+ {
1539
+ return sadd(self, -other);
1540
+ }
1541
+ else
1542
+ {
1543
+ const auto diff = min(self, other);
1544
+ return self - diff;
1545
+ }
1546
+ }
1547
+
1548
+ // store_aligned
1549
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
1550
+ XSIMD_INLINE void store_aligned(T* mem, batch<T, A> const& self, requires_arch<avx>) noexcept
1551
+ {
1552
+ return _mm256_store_si256((__m256i*)mem, self);
1553
+ }
1554
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
1555
+ XSIMD_INLINE void store_aligned(T* mem, batch_bool<T, A> const& self, requires_arch<avx>) noexcept
1556
+ {
1557
+ return _mm256_store_si256((__m256i*)mem, self);
1558
+ }
1559
+ template <class A>
1560
+ XSIMD_INLINE void store_aligned(float* mem, batch<float, A> const& self, requires_arch<avx>) noexcept
1561
+ {
1562
+ return _mm256_store_ps(mem, self);
1563
+ }
1564
+ template <class A>
1565
+ XSIMD_INLINE void store_aligned(double* mem, batch<double, A> const& self, requires_arch<avx>) noexcept
1566
+ {
1567
+ return _mm256_store_pd(mem, self);
1568
+ }
1569
+
1570
+ // store_unaligned
1571
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
1572
+ XSIMD_INLINE void store_unaligned(T* mem, batch<T, A> const& self, requires_arch<avx>) noexcept
1573
+ {
1574
+ return _mm256_storeu_si256((__m256i*)mem, self);
1575
+ }
1576
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
1577
+ XSIMD_INLINE void store_unaligned(T* mem, batch_bool<T, A> const& self, requires_arch<avx>) noexcept
1578
+ {
1579
+ return _mm256_storeu_si256((__m256i*)mem, self);
1580
+ }
1581
+ template <class A>
1582
+ XSIMD_INLINE void store_unaligned(float* mem, batch<float, A> const& self, requires_arch<avx>) noexcept
1583
+ {
1584
+ return _mm256_storeu_ps(mem, self);
1585
+ }
1586
+ template <class A>
1587
+ XSIMD_INLINE void store_unaligned(double* mem, batch<double, A> const& self, requires_arch<avx>) noexcept
1588
+ {
1589
+ return _mm256_storeu_pd(mem, self);
1590
+ }
1591
+
1592
+ // store_stream
1593
+ template <class A>
1594
+ XSIMD_INLINE void store_stream(float* mem, batch<float, A> const& self, requires_arch<avx>) noexcept
1595
+ {
1596
+ _mm256_stream_ps(mem, self);
1597
+ }
1598
+ template <class A>
1599
+ XSIMD_INLINE void store_stream(double* mem, batch<double, A> const& self, requires_arch<avx>) noexcept
1600
+ {
1601
+ _mm256_stream_pd(mem, self);
1602
+ }
1603
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value, void>>
1604
+ XSIMD_INLINE void store_stream(T* mem, batch<T, A> const& self, requires_arch<avx>) noexcept
1605
+ {
1606
+ _mm256_stream_si256((__m256i*)mem, self);
1607
+ }
1608
+
1609
+ // sub
1610
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
1611
+ XSIMD_INLINE batch<T, A> sub(batch<T, A> const& self, batch<T, A> const& other, requires_arch<avx>) noexcept
1612
+ {
1613
+ return detail::fwd_to_sse([](__m128i s, __m128i o) noexcept
1614
+ { return sub(batch<T, sse4_2>(s), batch<T, sse4_2>(o)); },
1615
+ self, other);
1616
+ }
1617
+ template <class A>
1618
+ XSIMD_INLINE batch<float, A> sub(batch<float, A> const& self, batch<float, A> const& other, requires_arch<avx>) noexcept
1619
+ {
1620
+ return _mm256_sub_ps(self, other);
1621
+ }
1622
+ template <class A>
1623
+ XSIMD_INLINE batch<double, A> sub(batch<double, A> const& self, batch<double, A> const& other, requires_arch<avx>) noexcept
1624
+ {
1625
+ return _mm256_sub_pd(self, other);
1626
+ }
1627
+
1628
+ // swizzle (dynamic mask)
1629
+ template <class A>
1630
+ XSIMD_INLINE batch<float, A> swizzle(batch<float, A> const& self, batch<uint32_t, A> mask, requires_arch<avx>) noexcept
1631
+ {
1632
+ // swap lanes
1633
+ __m256 swapped = _mm256_permute2f128_ps(self, self, 0x01); // [high | low]
1634
+
1635
+ // normalize mask taking modulo 4
1636
+ batch<uint32_t, A> half_mask = mask & 0b11u;
1637
+
1638
+ // permute within each lane
1639
+ __m256 r0 = _mm256_permutevar_ps(self, half_mask);
1640
+ __m256 r1 = _mm256_permutevar_ps(swapped, half_mask);
1641
+
1642
+ // select lane by the mask index divided by 4
1643
+ constexpr auto lane = batch_constant<uint32_t, A, 0, 0, 0, 0, 4, 4, 4, 4> {};
1644
+ batch_bool<uint32_t, A> blend_mask = (mask & 0b100u) != lane;
1645
+ return _mm256_blendv_ps(r0, r1, batch_bool_cast<float>(blend_mask));
1646
+ }
1647
+
1648
+ template <class A>
1649
+ XSIMD_INLINE batch<double, A> swizzle(batch<double, A> const& self, batch<uint64_t, A> mask, requires_arch<avx>) noexcept
1650
+ {
1651
+ // swap lanes
1652
+ __m256d swapped = _mm256_permute2f128_pd(self, self, 0x01); // [high | low]
1653
+
1654
+ // The half mask value is found in mask modulo 2, but the intrinsic expect it in the
1655
+ // second least significant bit. We use negative as a cheap alternative to lshift.
1656
+ batch<uint64_t, A> half_mask = -(mask & 0b1u);
1657
+
1658
+ // permute within each lane
1659
+ __m256d r0 = _mm256_permutevar_pd(self, half_mask);
1660
+ __m256d r1 = _mm256_permutevar_pd(swapped, half_mask);
1661
+
1662
+ // select lane by the mask index divided by 2
1663
+ constexpr auto lane = batch_constant<uint64_t, A, 0, 0, 2, 2> {};
1664
+ batch_bool<uint64_t, A> blend_mask = (mask & 0b10u) != lane;
1665
+ return _mm256_blendv_pd(r0, r1, batch_bool_cast<double>(blend_mask));
1666
+ }
1667
+
1668
+ template <class A, typename T, detail::enable_sized_integral_t<T, 4> = 0>
1669
+ XSIMD_INLINE batch<T, A> swizzle(batch<T, A> const& self, batch<uint32_t, A> const& mask, requires_arch<avx>) noexcept
1670
+ {
1671
+ return bitwise_cast<T>(
1672
+ swizzle(bitwise_cast<float>(self), mask));
1673
+ }
1674
+
1675
+ template <class A, typename T, detail::enable_sized_integral_t<T, 8> = 0>
1676
+ XSIMD_INLINE batch<T, A>
1677
+ swizzle(batch<T, A> const& self, batch<uint64_t, A> const& mask, requires_arch<avx>) noexcept
1678
+ {
1679
+ return bitwise_cast<T>(
1680
+ swizzle(bitwise_cast<double>(self), mask));
1681
+ }
1682
+
1683
+ // swizzle (constant mask)
1684
+ 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>
1685
+ XSIMD_INLINE batch<float, A> swizzle(batch<float, A> const& self, batch_constant<uint32_t, A, V0, V1, V2, V3, V4, V5, V6, V7> mask, requires_arch<avx>) noexcept
1686
+ {
1687
+ constexpr bool is_identity = detail::is_identity(mask);
1688
+ constexpr bool is_dup_low = detail::is_dup_lo(mask);
1689
+ constexpr bool is_dup_hi = detail::is_dup_hi(mask);
1690
+ constexpr bool is_dup = is_dup_low || is_dup_hi;
1691
+ XSIMD_IF_CONSTEXPR(is_identity)
1692
+ {
1693
+ return self;
1694
+ }
1695
+ XSIMD_IF_CONSTEXPR(is_dup)
1696
+ {
1697
+ constexpr auto control = is_dup_low ? 0x00 : 0x11;
1698
+ constexpr auto is_dup_identity = is_dup_low ? detail::is_identity<uint32_t, V0, V1, V2, V3>() : detail::is_identity<int64_t, V4 - 4, V5 - 4, V6 - 4, V7 - 4>();
1699
+ auto split = _mm256_permute2f128_ps(self, self, control);
1700
+ XSIMD_IF_CONSTEXPR(!is_dup_identity)
1701
+ {
1702
+ constexpr auto shuffle_mask = is_dup_low ? detail::mod_shuffle(V0, V1, V2, V3) : detail::mod_shuffle(V4 - 4, V5 - 4, V6 - 4, V7 - 4);
1703
+ split = _mm256_permute_ps(split, shuffle_mask);
1704
+ }
1705
+ return split;
1706
+ }
1707
+ constexpr auto lane_mask = mask % std::integral_constant<uint32_t, (mask.size / 2)>();
1708
+ XSIMD_IF_CONSTEXPR(detail::is_only_from_lo(mask))
1709
+ {
1710
+ __m256 broadcast = _mm256_permute2f128_ps(self, self, 0x00); // [low | low]
1711
+ return _mm256_permutevar_ps(broadcast, lane_mask.as_batch());
1712
+ }
1713
+ XSIMD_IF_CONSTEXPR(detail::is_only_from_hi(mask))
1714
+ {
1715
+ __m256 broadcast = _mm256_permute2f128_ps(self, self, 0x11); // [high | high]
1716
+ return _mm256_permutevar_ps(broadcast, lane_mask.as_batch());
1717
+ }
1718
+
1719
+ // Fallback to general algorithm. This is the same as the dynamic version with the exception
1720
+ // that possible operations are done at compile time.
1721
+
1722
+ // swap lanes
1723
+ __m256 swapped = _mm256_permute2f128_ps(self, self, 0x01); // [high | low]
1724
+
1725
+ // normalize mask taking modulo 4
1726
+ constexpr auto half_mask = mask % std::integral_constant<uint32_t, 4>();
1727
+
1728
+ // permute within each lane
1729
+ __m256 r0 = _mm256_permutevar_ps(self, half_mask.as_batch());
1730
+ __m256 r1 = _mm256_permutevar_ps(swapped, half_mask.as_batch());
1731
+
1732
+ // select lane by the mask index divided by 4
1733
+ constexpr auto lane = batch_constant<uint32_t, A, 0, 0, 0, 0, 1, 1, 1, 1> {};
1734
+ constexpr int lane_idx = ((mask / std::integral_constant<uint32_t, 4>()) != lane).mask();
1735
+
1736
+ return _mm256_blend_ps(r0, r1, lane_idx);
1737
+ }
1738
+
1739
+ template <class A, uint64_t V0, uint64_t V1, uint64_t V2, uint64_t V3>
1740
+ XSIMD_INLINE batch<double, A> swizzle(batch<double, A> const& self, batch_constant<uint64_t, A, V0, V1, V2, V3> mask, requires_arch<avx>) noexcept
1741
+ {
1742
+ // cannot use detail::mod_shuffle as the mod and shift are different in this case
1743
+ constexpr auto imm = ((V0 % 2) << 0) | ((V1 % 2) << 1) | ((V2 % 2) << 2) | ((V3 % 2) << 3);
1744
+ XSIMD_IF_CONSTEXPR(detail::is_identity(mask))
1745
+ {
1746
+ return self;
1747
+ }
1748
+ XSIMD_IF_CONSTEXPR(!detail::is_cross_lane(mask))
1749
+ {
1750
+ return _mm256_permute_pd(self, imm);
1751
+ }
1752
+ XSIMD_IF_CONSTEXPR(detail::is_only_from_lo(mask))
1753
+ {
1754
+ __m256d broadcast = _mm256_permute2f128_pd(self, self, 0x00); // [low | low]
1755
+ return _mm256_permute_pd(broadcast, imm);
1756
+ }
1757
+ XSIMD_IF_CONSTEXPR(detail::is_only_from_hi(mask))
1758
+ {
1759
+ __m256d broadcast = _mm256_permute2f128_pd(self, self, 0x11); // [high | high]
1760
+ return _mm256_permute_pd(broadcast, imm);
1761
+ }
1762
+
1763
+ // Fallback to general algorithm. This is the same as the dynamic version with the exception
1764
+ // that possible operations are done at compile time.
1765
+
1766
+ // swap lanes
1767
+ __m256d swapped = _mm256_permute2f128_pd(self, self, 0x01); // [high | low]
1768
+
1769
+ // permute within each lane
1770
+ __m256d r0 = _mm256_permute_pd(self, imm);
1771
+ __m256d r1 = _mm256_permute_pd(swapped, imm);
1772
+
1773
+ // select lane by the mask index divided by 2
1774
+ constexpr auto lane = batch_constant<uint64_t, A, 0, 0, 1, 1> {};
1775
+ constexpr int lane_idx = ((mask / std::integral_constant<uint64_t, 2>()) != lane).mask();
1776
+
1777
+ // blend the two permutes
1778
+ return _mm256_blend_pd(r0, r1, lane_idx);
1779
+ }
1780
+
1781
+ template <
1782
+ class A, typename T,
1783
+ uint32_t V0, uint32_t V1, uint32_t V2, uint32_t V3, uint32_t V4, uint32_t V5, uint32_t V6, uint32_t V7,
1784
+ detail::enable_sized_integral_t<T, 4> = 0>
1785
+ XSIMD_INLINE batch<T, A> swizzle(
1786
+ batch<T, A> const& self,
1787
+ batch_constant<uint32_t, A, V0, V1, V2, V3, V4, V5, V6, V7> const& mask,
1788
+ requires_arch<avx>) noexcept
1789
+ {
1790
+ return bitwise_cast<T>(swizzle(bitwise_cast<float>(self), mask));
1791
+ }
1792
+
1793
+ template <class A, typename T, uint64_t V0, uint64_t V1, uint64_t V2, uint64_t V3, detail::enable_sized_integral_t<T, 8> = 0>
1794
+ XSIMD_INLINE batch<T, A> swizzle(batch<T, A> const& self, batch_constant<uint64_t, A, V0, V1, V2, V3> const& mask, requires_arch<avx>) noexcept
1795
+ {
1796
+ return bitwise_cast<T>(swizzle(bitwise_cast<double>(self), mask));
1797
+ }
1798
+
1799
+ // transpose
1800
+ template <class A>
1801
+ XSIMD_INLINE void transpose(batch<float, A>* matrix_begin, batch<float, A>* matrix_end, requires_arch<avx>) noexcept
1802
+ {
1803
+ assert((matrix_end - matrix_begin == batch<float, A>::size) && "correctly sized matrix");
1804
+ (void)matrix_end;
1805
+ // See
1806
+ // https://stackoverflow.com/questions/25622745/transpose-an-8x8-float-using-avx-avx2
1807
+ auto r0 = matrix_begin[0], r1 = matrix_begin[1],
1808
+ r2 = matrix_begin[2], r3 = matrix_begin[3],
1809
+ r4 = matrix_begin[4], r5 = matrix_begin[5],
1810
+ r6 = matrix_begin[6], r7 = matrix_begin[7];
1811
+
1812
+ auto t0 = _mm256_unpacklo_ps(r0, r1);
1813
+ auto t1 = _mm256_unpackhi_ps(r0, r1);
1814
+ auto t2 = _mm256_unpacklo_ps(r2, r3);
1815
+ auto t3 = _mm256_unpackhi_ps(r2, r3);
1816
+ auto t4 = _mm256_unpacklo_ps(r4, r5);
1817
+ auto t5 = _mm256_unpackhi_ps(r4, r5);
1818
+ auto t6 = _mm256_unpacklo_ps(r6, r7);
1819
+ auto t7 = _mm256_unpackhi_ps(r6, r7);
1820
+
1821
+ r0 = _mm256_shuffle_ps(t0, t2, _MM_SHUFFLE(1, 0, 1, 0));
1822
+ r1 = _mm256_shuffle_ps(t0, t2, _MM_SHUFFLE(3, 2, 3, 2));
1823
+ r2 = _mm256_shuffle_ps(t1, t3, _MM_SHUFFLE(1, 0, 1, 0));
1824
+ r3 = _mm256_shuffle_ps(t1, t3, _MM_SHUFFLE(3, 2, 3, 2));
1825
+ r4 = _mm256_shuffle_ps(t4, t6, _MM_SHUFFLE(1, 0, 1, 0));
1826
+ r5 = _mm256_shuffle_ps(t4, t6, _MM_SHUFFLE(3, 2, 3, 2));
1827
+ r6 = _mm256_shuffle_ps(t5, t7, _MM_SHUFFLE(1, 0, 1, 0));
1828
+ r7 = _mm256_shuffle_ps(t5, t7, _MM_SHUFFLE(3, 2, 3, 2));
1829
+
1830
+ matrix_begin[0] = _mm256_permute2f128_ps(r0, r4, 0x20);
1831
+ matrix_begin[1] = _mm256_permute2f128_ps(r1, r5, 0x20);
1832
+ matrix_begin[2] = _mm256_permute2f128_ps(r2, r6, 0x20);
1833
+ matrix_begin[3] = _mm256_permute2f128_ps(r3, r7, 0x20);
1834
+ matrix_begin[4] = _mm256_permute2f128_ps(r0, r4, 0x31);
1835
+ matrix_begin[5] = _mm256_permute2f128_ps(r1, r5, 0x31);
1836
+ matrix_begin[6] = _mm256_permute2f128_ps(r2, r6, 0x31);
1837
+ matrix_begin[7] = _mm256_permute2f128_ps(r3, r7, 0x31);
1838
+ }
1839
+
1840
+ template <class A>
1841
+ XSIMD_INLINE void transpose(batch<uint32_t, A>* matrix_begin, batch<uint32_t, A>* matrix_end, requires_arch<avx>) noexcept
1842
+ {
1843
+ return transpose(reinterpret_cast<batch<float, A>*>(matrix_begin), reinterpret_cast<batch<float, A>*>(matrix_end), A {});
1844
+ }
1845
+ template <class A>
1846
+ XSIMD_INLINE void transpose(batch<int32_t, A>* matrix_begin, batch<int32_t, A>* matrix_end, requires_arch<avx>) noexcept
1847
+ {
1848
+ return transpose(reinterpret_cast<batch<float, A>*>(matrix_begin), reinterpret_cast<batch<float, A>*>(matrix_end), A {});
1849
+ }
1850
+
1851
+ template <class A>
1852
+ XSIMD_INLINE void transpose(batch<double, A>* matrix_begin, batch<double, A>* matrix_end, requires_arch<avx>) noexcept
1853
+ {
1854
+ assert((matrix_end - matrix_begin == batch<double, A>::size) && "correctly sized matrix");
1855
+ (void)matrix_end;
1856
+ auto r0 = matrix_begin[0], r1 = matrix_begin[1],
1857
+ r2 = matrix_begin[2], r3 = matrix_begin[3];
1858
+
1859
+ auto t0 = _mm256_unpacklo_pd(r0, r1); // r00 r10 r01 r11
1860
+ auto t1 = _mm256_unpackhi_pd(r0, r1); // r02 r12 r03 r13
1861
+ auto t2 = _mm256_unpacklo_pd(r2, r3); // r20 r30 r21 r31
1862
+ auto t3 = _mm256_unpackhi_pd(r2, r3); // r22 r32 r23 r33
1863
+
1864
+ matrix_begin[0] = _mm256_permute2f128_pd(t0, t2, 0x20);
1865
+ matrix_begin[1] = _mm256_permute2f128_pd(t1, t3, 0x20);
1866
+ matrix_begin[2] = _mm256_permute2f128_pd(t0, t2, 0x31);
1867
+ matrix_begin[3] = _mm256_permute2f128_pd(t1, t3, 0x31);
1868
+ }
1869
+
1870
+ template <class A>
1871
+ XSIMD_INLINE void transpose(batch<uint64_t, A>* matrix_begin, batch<uint64_t, A>* matrix_end, requires_arch<avx>) noexcept
1872
+ {
1873
+ return transpose(reinterpret_cast<batch<double, A>*>(matrix_begin), reinterpret_cast<batch<double, A>*>(matrix_end), A {});
1874
+ }
1875
+ template <class A>
1876
+ XSIMD_INLINE void transpose(batch<int64_t, A>* matrix_begin, batch<int64_t, A>* matrix_end, requires_arch<avx>) noexcept
1877
+ {
1878
+ return transpose(reinterpret_cast<batch<double, A>*>(matrix_begin), reinterpret_cast<batch<double, A>*>(matrix_end), A {});
1879
+ }
1880
+
1881
+ template <class A>
1882
+ XSIMD_INLINE void transpose(batch<uint16_t, A>* matrix_begin, batch<uint16_t, A>* matrix_end, requires_arch<avx>) noexcept
1883
+ {
1884
+ assert((matrix_end - matrix_begin == batch<uint16_t, A>::size) && "correctly sized matrix");
1885
+ (void)matrix_end;
1886
+ batch<uint16_t, sse4_2> tmp_lo0[8];
1887
+ for (int i = 0; i < 8; ++i)
1888
+ tmp_lo0[i] = _mm256_castsi256_si128(matrix_begin[i]);
1889
+ transpose(tmp_lo0 + 0, tmp_lo0 + 8, sse4_2 {});
1890
+
1891
+ batch<uint16_t, sse4_2> tmp_hi0[8];
1892
+ for (int i = 0; i < 8; ++i)
1893
+ tmp_hi0[i] = _mm256_castsi256_si128(matrix_begin[8 + i]);
1894
+ transpose(tmp_hi0 + 0, tmp_hi0 + 8, sse4_2 {});
1895
+
1896
+ batch<uint16_t, sse4_2> tmp_lo1[8];
1897
+ for (int i = 0; i < 8; ++i)
1898
+ tmp_lo1[i] = _mm256_extractf128_si256(matrix_begin[i], 1);
1899
+ transpose(tmp_lo1 + 0, tmp_lo1 + 8, sse4_2 {});
1900
+
1901
+ batch<uint16_t, sse4_2> tmp_hi1[8];
1902
+ for (int i = 0; i < 8; ++i)
1903
+ tmp_hi1[i] = _mm256_extractf128_si256(matrix_begin[8 + i], 1);
1904
+ transpose(tmp_hi1 + 0, tmp_hi1 + 8, sse4_2 {});
1905
+
1906
+ for (int i = 0; i < 8; ++i)
1907
+ matrix_begin[i] = detail::merge_sse(tmp_lo0[i], tmp_hi0[i]);
1908
+ for (int i = 0; i < 8; ++i)
1909
+ matrix_begin[i + 8] = detail::merge_sse(tmp_lo1[i], tmp_hi1[i]);
1910
+ }
1911
+ template <class A>
1912
+ XSIMD_INLINE void transpose(batch<int16_t, A>* matrix_begin, batch<int16_t, A>* matrix_end, requires_arch<avx>) noexcept
1913
+ {
1914
+ return transpose(reinterpret_cast<batch<uint16_t, A>*>(matrix_begin), reinterpret_cast<batch<uint16_t, A>*>(matrix_end), A {});
1915
+ }
1916
+
1917
+ template <class A>
1918
+ XSIMD_INLINE void transpose(batch<uint8_t, A>* matrix_begin, batch<uint8_t, A>* matrix_end, requires_arch<avx>) noexcept
1919
+ {
1920
+ assert((matrix_end - matrix_begin == batch<uint8_t, A>::size) && "correctly sized matrix");
1921
+ (void)matrix_end;
1922
+ batch<uint8_t, sse4_2> tmp_lo0[16];
1923
+ for (int i = 0; i < 16; ++i)
1924
+ tmp_lo0[i] = _mm256_castsi256_si128(matrix_begin[i]);
1925
+ transpose(tmp_lo0 + 0, tmp_lo0 + 16, sse4_2 {});
1926
+
1927
+ batch<uint8_t, sse4_2> tmp_hi0[16];
1928
+ for (int i = 0; i < 16; ++i)
1929
+ tmp_hi0[i] = _mm256_castsi256_si128(matrix_begin[16 + i]);
1930
+ transpose(tmp_hi0 + 0, tmp_hi0 + 16, sse4_2 {});
1931
+
1932
+ batch<uint8_t, sse4_2> tmp_lo1[16];
1933
+ for (int i = 0; i < 16; ++i)
1934
+ tmp_lo1[i] = _mm256_extractf128_si256(matrix_begin[i], 1);
1935
+ transpose(tmp_lo1 + 0, tmp_lo1 + 16, sse4_2 {});
1936
+
1937
+ batch<uint8_t, sse4_2> tmp_hi1[16];
1938
+ for (int i = 0; i < 16; ++i)
1939
+ tmp_hi1[i] = _mm256_extractf128_si256(matrix_begin[16 + i], 1);
1940
+ transpose(tmp_hi1 + 0, tmp_hi1 + 16, sse4_2 {});
1941
+
1942
+ for (int i = 0; i < 16; ++i)
1943
+ matrix_begin[i] = detail::merge_sse(tmp_lo0[i], tmp_hi0[i]);
1944
+ for (int i = 0; i < 16; ++i)
1945
+ matrix_begin[i + 16] = detail::merge_sse(tmp_lo1[i], tmp_hi1[i]);
1946
+ }
1947
+ template <class A>
1948
+ XSIMD_INLINE void transpose(batch<int8_t, A>* matrix_begin, batch<int8_t, A>* matrix_end, requires_arch<avx>) noexcept
1949
+ {
1950
+ return transpose(reinterpret_cast<batch<uint8_t, A>*>(matrix_begin), reinterpret_cast<batch<uint8_t, A>*>(matrix_end), A {});
1951
+ }
1952
+
1953
+ // trunc
1954
+ template <class A>
1955
+ XSIMD_INLINE batch<float, A> trunc(batch<float, A> const& self, requires_arch<avx>) noexcept
1956
+ {
1957
+ return _mm256_round_ps(self, _MM_FROUND_TO_ZERO);
1958
+ }
1959
+ template <class A>
1960
+ XSIMD_INLINE batch<double, A> trunc(batch<double, A> const& self, requires_arch<avx>) noexcept
1961
+ {
1962
+ return _mm256_round_pd(self, _MM_FROUND_TO_ZERO);
1963
+ }
1964
+
1965
+ // zip_hi
1966
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
1967
+ XSIMD_INLINE batch<T, A> zip_hi(batch<T, A> const& self, batch<T, A> const& other, requires_arch<avx>) noexcept
1968
+ {
1969
+ XSIMD_IF_CONSTEXPR(sizeof(T) == 1 || sizeof(T) == 2)
1970
+ {
1971
+ // extract high word
1972
+ __m128i self_hi = _mm256_extractf128_si256(self, 1);
1973
+ __m128i other_hi = _mm256_extractf128_si256(other, 1);
1974
+
1975
+ // interleave
1976
+ __m128i res_lo, res_hi;
1977
+ XSIMD_IF_CONSTEXPR(sizeof(T) == 1)
1978
+ {
1979
+ res_lo = _mm_unpacklo_epi8(self_hi, other_hi);
1980
+ res_hi = _mm_unpackhi_epi8(self_hi, other_hi);
1981
+ }
1982
+ else
1983
+ {
1984
+ res_lo = _mm_unpacklo_epi16(self_hi, other_hi);
1985
+ res_hi = _mm_unpackhi_epi16(self_hi, other_hi);
1986
+ }
1987
+
1988
+ // fuse
1989
+ return _mm256_castps_si256(
1990
+ _mm256_insertf128_ps(
1991
+ _mm256_castsi256_ps(_mm256_castsi128_si256(res_lo)),
1992
+ _mm_castsi128_ps(res_hi),
1993
+ 1));
1994
+ }
1995
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
1996
+ {
1997
+ auto lo = _mm256_unpacklo_ps(_mm256_castsi256_ps(self), _mm256_castsi256_ps(other));
1998
+ auto hi = _mm256_unpackhi_ps(_mm256_castsi256_ps(self), _mm256_castsi256_ps(other));
1999
+ return _mm256_castps_si256(_mm256_permute2f128_ps(lo, hi, 0x31));
2000
+ }
2001
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 8)
2002
+ {
2003
+ auto lo = _mm256_unpacklo_pd(_mm256_castsi256_pd(self), _mm256_castsi256_pd(other));
2004
+ auto hi = _mm256_unpackhi_pd(_mm256_castsi256_pd(self), _mm256_castsi256_pd(other));
2005
+ return _mm256_castpd_si256(_mm256_permute2f128_pd(lo, hi, 0x31));
2006
+ }
2007
+ else
2008
+ {
2009
+ assert(false && "unsupported arch/op combination");
2010
+ return {};
2011
+ }
2012
+ }
2013
+ template <class A>
2014
+ XSIMD_INLINE batch<float, A> zip_hi(batch<float, A> const& self, batch<float, A> const& other, requires_arch<avx>) noexcept
2015
+ {
2016
+ auto lo = _mm256_unpacklo_ps(self, other);
2017
+ auto hi = _mm256_unpackhi_ps(self, other);
2018
+ return _mm256_permute2f128_ps(lo, hi, 0x31);
2019
+ }
2020
+ template <class A>
2021
+ XSIMD_INLINE batch<double, A> zip_hi(batch<double, A> const& self, batch<double, A> const& other, requires_arch<avx>) noexcept
2022
+ {
2023
+ auto lo = _mm256_unpacklo_pd(self, other);
2024
+ auto hi = _mm256_unpackhi_pd(self, other);
2025
+ return _mm256_permute2f128_pd(lo, hi, 0x31);
2026
+ }
2027
+
2028
+ // zip_lo
2029
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
2030
+ XSIMD_INLINE batch<T, A> zip_lo(batch<T, A> const& self, batch<T, A> const& other, requires_arch<avx>) noexcept
2031
+ {
2032
+ XSIMD_IF_CONSTEXPR(sizeof(T) == 1 || sizeof(T) == 2)
2033
+ {
2034
+ // extract low word
2035
+ __m128i self_lo = _mm256_extractf128_si256(self, 0);
2036
+ __m128i other_lo = _mm256_extractf128_si256(other, 0);
2037
+
2038
+ // interleave
2039
+ __m128i res_lo, res_hi;
2040
+ XSIMD_IF_CONSTEXPR(sizeof(T) == 1)
2041
+ {
2042
+ res_lo = _mm_unpacklo_epi8(self_lo, other_lo);
2043
+ res_hi = _mm_unpackhi_epi8(self_lo, other_lo);
2044
+ }
2045
+ else
2046
+ {
2047
+ res_lo = _mm_unpacklo_epi16(self_lo, other_lo);
2048
+ res_hi = _mm_unpackhi_epi16(self_lo, other_lo);
2049
+ }
2050
+
2051
+ // fuse
2052
+ return _mm256_castps_si256(
2053
+ _mm256_insertf128_ps(
2054
+ _mm256_castsi256_ps(_mm256_castsi128_si256(res_lo)),
2055
+ _mm_castsi128_ps(res_hi),
2056
+ 1));
2057
+ }
2058
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
2059
+ {
2060
+ auto lo = _mm256_unpacklo_ps(_mm256_castsi256_ps(self), _mm256_castsi256_ps(other));
2061
+ auto hi = _mm256_unpackhi_ps(_mm256_castsi256_ps(self), _mm256_castsi256_ps(other));
2062
+ return _mm256_castps_si256(_mm256_insertf128_ps(lo, _mm256_castps256_ps128(hi), 1));
2063
+ }
2064
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 8)
2065
+ {
2066
+ auto lo = _mm256_unpacklo_pd(_mm256_castsi256_pd(self), _mm256_castsi256_pd(other));
2067
+ auto hi = _mm256_unpackhi_pd(_mm256_castsi256_pd(self), _mm256_castsi256_pd(other));
2068
+ return _mm256_castpd_si256(_mm256_insertf128_pd(lo, _mm256_castpd256_pd128(hi), 1));
2069
+ }
2070
+ else
2071
+ {
2072
+ assert(false && "unsupported arch/op combination");
2073
+ return {};
2074
+ }
2075
+ }
2076
+
2077
+ template <class A>
2078
+ XSIMD_INLINE batch<float, A> zip_lo(batch<float, A> const& self, batch<float, A> const& other, requires_arch<avx>) noexcept
2079
+ {
2080
+ auto lo = _mm256_unpacklo_ps(self, other);
2081
+ auto hi = _mm256_unpackhi_ps(self, other);
2082
+ return _mm256_insertf128_ps(lo, _mm256_castps256_ps128(hi), 1);
2083
+ }
2084
+ template <class A>
2085
+ XSIMD_INLINE batch<double, A> zip_lo(batch<double, A> const& self, batch<double, A> const& other, requires_arch<avx>) noexcept
2086
+ {
2087
+ auto lo = _mm256_unpacklo_pd(self, other);
2088
+ auto hi = _mm256_unpackhi_pd(self, other);
2089
+ return _mm256_insertf128_pd(lo, _mm256_castpd256_pd128(hi), 1);
2090
+ }
2091
+
2092
+ // widen
2093
+ template <class A, class T>
2094
+ XSIMD_INLINE std::array<batch<widen_t<T>, A>, 2> widen(batch<T, A> const& x, requires_arch<avx>) noexcept
2095
+ {
2096
+ auto pair_lo = widen(batch<T, sse4_2>(detail::lower_half(x)), sse4_2 {});
2097
+ auto pair_hi = widen(batch<T, sse4_2>(detail::upper_half(x)), sse4_2 {});
2098
+ return { detail::merge_sse(pair_lo[0], pair_lo[1]), detail::merge_sse(pair_hi[0], pair_hi[1]) };
2099
+ }
2100
+ template <class A>
2101
+ XSIMD_INLINE std::array<batch<double, A>, 2> widen(batch<float, A> const& x, requires_arch<avx>) noexcept
2102
+ {
2103
+ __m256d lo = _mm256_cvtps_pd(detail::lower_half(x));
2104
+ __m256d hi = _mm256_cvtps_pd(detail::upper_half(x));
2105
+ return { lo, hi };
2106
+ }
2107
+
2108
+ }
2109
+ }
2110
+
2111
+ #endif