react-native-executorch 0.10.5 → 0.10.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (251) hide show
  1. package/README.md +10 -1
  2. package/android/build.gradle.kts +4 -3
  3. package/ios/RnExecutorch.mm +15 -17
  4. package/lib/module/fetcher/fetcher.js +35 -122
  5. package/lib/module/fetcher/fetcher.js.map +1 -1
  6. package/lib/module/fetcher/telemetry.js +1 -1
  7. package/lib/module/index.js +12 -13
  8. package/lib/module/index.js.map +1 -1
  9. package/lib/module/models.js +4 -2
  10. package/lib/module/models.js.map +1 -1
  11. package/lib/typescript/src/fetcher/fetcher.d.ts +3 -7
  12. package/lib/typescript/src/fetcher/fetcher.d.ts.map +1 -1
  13. package/lib/typescript/src/models.d.ts.map +1 -1
  14. package/package.json +9 -7
  15. package/react-native-executorch.podspec +6 -2
  16. package/src/fetcher/fetcher.ts +38 -131
  17. package/src/fetcher/telemetry.ts +1 -1
  18. package/src/models.ts +6 -1
  19. package/third-party/common/phonemis/CMakeLists.txt +70 -14
  20. package/third-party/common/phonemis/README.md +183 -33
  21. package/third-party/common/phonemis/THIRD_PARTY_NOTICES.md +57 -0
  22. package/third-party/common/phonemis/knowledge/code_style.md +642 -0
  23. package/third-party/common/phonemis/licenses/Unicode-3.0.txt +39 -0
  24. package/third-party/common/phonemis/licenses/misaki-Apache-2.0.txt +201 -0
  25. package/third-party/common/phonemis/licenses/nlohmann-json-MIT.txt +21 -0
  26. package/third-party/common/phonemis/licenses/xsimd-BSD-3-Clause.txt +29 -0
  27. package/third-party/common/phonemis/src/phonemis/base/config.h +6 -0
  28. package/third-party/common/phonemis/src/phonemis/base/ipipeline.cpp +75 -0
  29. package/third-party/common/phonemis/src/phonemis/base/ipipeline.h +21 -0
  30. package/third-party/common/phonemis/src/phonemis/base/phonemizer/constants.h +2 -5
  31. package/third-party/common/phonemis/src/phonemis/base/phonemizer/lexicon_phonemizer.cpp +3 -4
  32. package/third-party/common/phonemis/src/phonemis/base/phonemizer/nn/neural_phonemizer.cpp +17 -8
  33. package/third-party/common/phonemis/src/phonemis/base/phonemizer/nn/neural_phonemizer.h +4 -0
  34. package/third-party/common/phonemis/src/phonemis/base/phonemizer/nn/tokenizer.cpp +21 -6
  35. package/third-party/common/phonemis/src/phonemis/base/phonemizer/nn/tokenizer.h +13 -4
  36. package/third-party/common/phonemis/src/phonemis/base/pipeline.cpp +8 -0
  37. package/third-party/common/phonemis/src/phonemis/base/pipeline.h +19 -0
  38. package/third-party/common/phonemis/src/phonemis/base/processor/common/conditions.cpp +37 -0
  39. package/third-party/common/phonemis/src/phonemis/base/processor/common/conditions.h +45 -0
  40. package/third-party/common/phonemis/src/phonemis/base/processor/common/constants.h +10 -0
  41. package/third-party/common/phonemis/src/phonemis/base/processor/common/context.cpp +105 -0
  42. package/third-party/common/phonemis/src/phonemis/base/processor/common/context.h +49 -0
  43. package/third-party/common/phonemis/src/phonemis/base/processor/common/document.cpp +173 -0
  44. package/third-party/common/phonemis/src/phonemis/base/processor/common/document.h +67 -0
  45. package/third-party/common/phonemis/src/phonemis/base/processor/common/text.cpp +75 -0
  46. package/third-party/common/phonemis/src/phonemis/base/processor/common/text.h +60 -0
  47. package/third-party/common/phonemis/src/phonemis/base/processor/common/types.h +18 -0
  48. package/third-party/common/phonemis/src/phonemis/base/processor/config.h +53 -0
  49. package/third-party/common/phonemis/src/phonemis/base/processor/layer.h +9 -7
  50. package/third-party/common/phonemis/src/phonemis/base/processor/layers/normalize/constants.h +20 -0
  51. package/third-party/common/phonemis/src/phonemis/base/processor/layers/normalize/layer.cpp +89 -0
  52. package/third-party/common/phonemis/src/phonemis/base/processor/layers/normalize/layer.h +35 -0
  53. package/third-party/common/phonemis/src/phonemis/base/processor/layers/normalize/types.h +16 -0
  54. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/kind.h +40 -0
  55. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/layer.h +382 -0
  56. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/notation.h +30 -0
  57. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/numerals.cpp +51 -0
  58. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/numerals.h +31 -0
  59. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/pattern.h +30 -0
  60. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/pattern_set.cpp +17 -0
  61. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/pattern_set.h +31 -0
  62. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/patterns.cpp +811 -0
  63. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/patterns.h +285 -0
  64. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/primitives.cpp +64 -0
  65. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/primitives.h +23 -0
  66. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/types.h +94 -0
  67. package/third-party/common/phonemis/src/phonemis/base/processor/layers/sanitizer/layer.cpp +19 -0
  68. package/third-party/common/phonemis/src/phonemis/base/processor/{sanitizer_layer.h → layers/sanitizer/layer.h} +8 -8
  69. package/third-party/common/phonemis/src/phonemis/base/processor/layers/sym2word/layer.cpp +65 -0
  70. package/third-party/common/phonemis/src/phonemis/base/processor/layers/sym2word/layer.h +29 -0
  71. package/third-party/common/phonemis/src/phonemis/base/processor/layers/term2word/layer.cpp +170 -0
  72. package/third-party/common/phonemis/src/phonemis/base/processor/layers/term2word/layer.h +40 -0
  73. package/third-party/common/phonemis/src/phonemis/base/processor/layers/term2word/types.h +25 -0
  74. package/third-party/common/phonemis/src/phonemis/base/processor/layers/trim/layer.cpp +47 -0
  75. package/third-party/common/phonemis/src/phonemis/base/processor/layers/trim/layer.h +19 -0
  76. package/third-party/common/phonemis/src/phonemis/base/processor/preprocessor.cpp +60 -0
  77. package/third-party/common/phonemis/src/phonemis/base/processor/preprocessor.h +45 -0
  78. package/third-party/common/phonemis/src/phonemis/base/processor/processor.cpp +6 -7
  79. package/third-party/common/phonemis/src/phonemis/base/processor/processor.h +14 -10
  80. package/third-party/common/phonemis/src/phonemis/base/tagger/hmm_tagger.cpp +89 -52
  81. package/third-party/common/phonemis/src/phonemis/base/tagger/hmm_tagger.h +16 -9
  82. package/third-party/common/phonemis/src/phonemis/base/tokenizer/tokenizer.cpp +13 -12
  83. package/third-party/common/phonemis/src/phonemis/lang/de/constants.h +183 -19
  84. package/third-party/common/phonemis/src/phonemis/lang/de/num2word.cpp +355 -309
  85. package/third-party/common/phonemis/src/phonemis/lang/de/num2word.h +42 -17
  86. package/third-party/common/phonemis/src/phonemis/lang/de/patterns.cpp +56 -0
  87. package/third-party/common/phonemis/src/phonemis/lang/de/patterns.h +15 -0
  88. package/third-party/common/phonemis/src/phonemis/lang/de/pipeline.h +3 -3
  89. package/third-party/common/phonemis/src/phonemis/lang/en/constants.h +181 -30
  90. package/third-party/common/phonemis/src/phonemis/lang/en/hmm_tagger.cpp +5 -7
  91. package/third-party/common/phonemis/src/phonemis/lang/en/num2word.cpp +232 -135
  92. package/third-party/common/phonemis/src/phonemis/lang/en/num2word.h +41 -16
  93. package/third-party/common/phonemis/src/phonemis/lang/en/pipeline.h +3 -10
  94. package/third-party/common/phonemis/src/phonemis/lang/es/constants.h +182 -60
  95. package/third-party/common/phonemis/src/phonemis/lang/es/num2word.cpp +247 -212
  96. package/third-party/common/phonemis/src/phonemis/lang/es/num2word.h +38 -18
  97. package/third-party/common/phonemis/src/phonemis/lang/es/patterns.cpp +50 -0
  98. package/third-party/common/phonemis/src/phonemis/lang/es/patterns.h +15 -0
  99. package/third-party/common/phonemis/src/phonemis/lang/es/pipeline.h +3 -3
  100. package/third-party/common/phonemis/src/phonemis/lang/fr/constants.h +152 -26
  101. package/third-party/common/phonemis/src/phonemis/lang/fr/num2word.cpp +252 -179
  102. package/third-party/common/phonemis/src/phonemis/lang/fr/num2word.h +38 -15
  103. package/third-party/common/phonemis/src/phonemis/lang/fr/patterns.cpp +83 -0
  104. package/third-party/common/phonemis/src/phonemis/lang/fr/patterns.h +15 -0
  105. package/third-party/common/phonemis/src/phonemis/lang/fr/pipeline.h +3 -3
  106. package/third-party/common/phonemis/src/phonemis/lang/hi/constants.h +62 -10
  107. package/third-party/common/phonemis/src/phonemis/lang/hi/num2word.cpp +74 -123
  108. package/third-party/common/phonemis/src/phonemis/lang/hi/num2word.h +27 -16
  109. package/third-party/common/phonemis/src/phonemis/lang/hi/pipeline.h +5 -3
  110. package/third-party/common/phonemis/src/phonemis/lang/it/constants.h +122 -42
  111. package/third-party/common/phonemis/src/phonemis/lang/it/num2word.cpp +200 -207
  112. package/third-party/common/phonemis/src/phonemis/lang/it/num2word.h +30 -18
  113. package/third-party/common/phonemis/src/phonemis/lang/it/patterns.cpp +25 -0
  114. package/third-party/common/phonemis/src/phonemis/lang/it/patterns.h +15 -0
  115. package/third-party/common/phonemis/src/phonemis/lang/it/pipeline.h +3 -3
  116. package/third-party/common/phonemis/src/phonemis/lang/pl/constants.h +346 -77
  117. package/third-party/common/phonemis/src/phonemis/lang/pl/num2word.cpp +631 -246
  118. package/third-party/common/phonemis/src/phonemis/lang/pl/num2word.h +47 -15
  119. package/third-party/common/phonemis/src/phonemis/lang/pl/pipeline.h +6 -6
  120. package/third-party/common/phonemis/src/phonemis/lang/pt/constants.h +201 -0
  121. package/third-party/common/phonemis/src/phonemis/lang/pt/num2word.cpp +365 -0
  122. package/third-party/common/phonemis/src/phonemis/lang/pt/num2word.h +53 -0
  123. package/third-party/common/phonemis/src/phonemis/lang/pt/pipeline.h +4 -2
  124. package/third-party/common/phonemis/src/phonemis/main.cpp +42 -11
  125. package/third-party/common/phonemis/src/phonemis/protophone/meta.h +24 -0
  126. package/third-party/common/phonemis/src/phonemis/protophone/numeric.h +26 -0
  127. package/third-party/common/phonemis/src/phonemis/protophone/protophone.cpp +525 -0
  128. package/third-party/common/phonemis/src/phonemis/protophone/protophone.h +80 -0
  129. package/third-party/common/phonemis/src/phonemis/protophone/tensor.h +76 -0
  130. package/third-party/common/phonemis/src/phonemis/protophone/tensor_utils.h +89 -0
  131. package/third-party/common/phonemis/src/phonemis/protophone/tensor_view.h +125 -0
  132. package/third-party/common/phonemis/src/phonemis/protophone/types.h +43 -0
  133. package/third-party/common/phonemis/src/phonemis/utils/strings.h +20 -14
  134. package/third-party/common/phonemis/src/phonemis/utils/unicode.h +15 -1
  135. package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_arithmetic.hpp +267 -0
  136. package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_bit.hpp +232 -0
  137. package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_cast.hpp +43 -0
  138. package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_complex.hpp +112 -0
  139. package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_details.hpp +386 -0
  140. package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_logical.hpp +240 -0
  141. package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_math.hpp +2601 -0
  142. package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_memory.hpp +1006 -0
  143. package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_rounding.hpp +72 -0
  144. package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_swizzle.hpp +260 -0
  145. package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_trigo.hpp +996 -0
  146. package/third-party/common/phonemis/src/third-party/xsimd/arch/utils/shifts.hpp +82 -0
  147. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx.hpp +2111 -0
  148. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx2.hpp +1591 -0
  149. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx2_128.hpp +170 -0
  150. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512bw.hpp +724 -0
  151. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512cd.hpp +28 -0
  152. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512dq.hpp +270 -0
  153. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512er.hpp +17 -0
  154. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512f.hpp +2919 -0
  155. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512ifma.hpp +17 -0
  156. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512pf.hpp +17 -0
  157. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512vbmi.hpp +76 -0
  158. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512vbmi2.hpp +130 -0
  159. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512vnni_avx512bw.hpp +17 -0
  160. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512vnni_avx512vbmi2.hpp +17 -0
  161. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx_128.hpp +164 -0
  162. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avxvnni.hpp +17 -0
  163. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_common.hpp +26 -0
  164. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_common_fwd.hpp +127 -0
  165. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_constants.hpp +393 -0
  166. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_emulated.hpp +787 -0
  167. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_fma3_avx.hpp +93 -0
  168. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_fma3_avx2.hpp +46 -0
  169. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_fma3_sse.hpp +97 -0
  170. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_fma4.hpp +92 -0
  171. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_i8mm_neon64.hpp +17 -0
  172. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_isa.hpp +148 -0
  173. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_neon.hpp +3580 -0
  174. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_neon64.hpp +1614 -0
  175. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_rvv.hpp +1515 -0
  176. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_scalar.hpp +1210 -0
  177. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_sse2.hpp +2333 -0
  178. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_sse3.hpp +66 -0
  179. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_sse4_1.hpp +510 -0
  180. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_sse4_2.hpp +44 -0
  181. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_ssse3.hpp +186 -0
  182. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_sve.hpp +1186 -0
  183. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_vsx.hpp +947 -0
  184. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_vxe.hpp +787 -0
  185. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_wasm.hpp +1819 -0
  186. package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_arch.hpp +242 -0
  187. package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_config.hpp +633 -0
  188. package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_cpu_features.hpp +50 -0
  189. package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_cpu_features_arm.hpp +132 -0
  190. package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_cpu_features_ppc.hpp +54 -0
  191. package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_cpu_features_riscv.hpp +95 -0
  192. package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_cpu_features_s390x.hpp +56 -0
  193. package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_cpu_features_x86.hpp +1121 -0
  194. package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_cpuid.hpp +144 -0
  195. package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_getauxval.hpp +159 -0
  196. package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_macros.hpp +78 -0
  197. package/third-party/common/phonemis/src/third-party/xsimd/math/xsimd_rem_pio2.hpp +707 -0
  198. package/third-party/common/phonemis/src/third-party/xsimd/memory/xsimd_aligned_allocator.hpp +349 -0
  199. package/third-party/common/phonemis/src/third-party/xsimd/memory/xsimd_alignment.hpp +102 -0
  200. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_all_registers.hpp +57 -0
  201. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_api.hpp +3106 -0
  202. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx2_register.hpp +57 -0
  203. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512bw_register.hpp +51 -0
  204. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512cd_register.hpp +51 -0
  205. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512dq_register.hpp +51 -0
  206. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512er_register.hpp +51 -0
  207. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512f_register.hpp +77 -0
  208. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512ifma_register.hpp +51 -0
  209. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512pf_register.hpp +51 -0
  210. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512vbmi2_register.hpp +51 -0
  211. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512vbmi_register.hpp +51 -0
  212. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512vnni_avx512bw_register.hpp +54 -0
  213. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512vnni_avx512vbmi2_register.hpp +53 -0
  214. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx_register.hpp +79 -0
  215. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avxvnni_register.hpp +44 -0
  216. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_batch.hpp +1666 -0
  217. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_batch_constant.hpp +572 -0
  218. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_batch_fwd.hpp +41 -0
  219. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_common_arch.hpp +49 -0
  220. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_emulated_register.hpp +80 -0
  221. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_fma3_avx2_register.hpp +50 -0
  222. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_fma3_avx_register.hpp +50 -0
  223. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_fma3_sse_register.hpp +50 -0
  224. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_fma4_register.hpp +50 -0
  225. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_i8mm_neon64_register.hpp +55 -0
  226. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_neon64_register.hpp +55 -0
  227. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_neon_register.hpp +130 -0
  228. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_register.hpp +96 -0
  229. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_rvv_register.hpp +491 -0
  230. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_sse2_register.hpp +59 -0
  231. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_sse3_register.hpp +49 -0
  232. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_sse4_1_register.hpp +48 -0
  233. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_sse4_2_register.hpp +48 -0
  234. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_ssse3_register.hpp +48 -0
  235. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_sve_register.hpp +216 -0
  236. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_traits.hpp +409 -0
  237. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_utils.hpp +462 -0
  238. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_vsx_register.hpp +84 -0
  239. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_vxe_register.hpp +86 -0
  240. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_wasm_register.hpp +59 -0
  241. package/third-party/common/phonemis/src/third-party/xsimd/utils/bits.hpp +122 -0
  242. package/third-party/common/phonemis/src/third-party/xsimd/utils/xsimd_type_traits.hpp +145 -0
  243. package/third-party/common/phonemis/src/third-party/xsimd/xsimd.hpp +43 -0
  244. package/third-party/common/phonemis/src/phonemis/base/processor/constants.h +0 -11
  245. package/third-party/common/phonemis/src/phonemis/base/processor/num2word/config.h +0 -16
  246. package/third-party/common/phonemis/src/phonemis/base/processor/num2word/layer.cpp +0 -271
  247. package/third-party/common/phonemis/src/phonemis/base/processor/num2word/layer.h +0 -45
  248. package/third-party/common/phonemis/src/phonemis/base/processor/num2word/types.h +0 -29
  249. package/third-party/common/phonemis/src/phonemis/base/processor/sanitizer_layer.cpp +0 -22
  250. package/third-party/common/phonemis/src/phonemis/base/processor/trim_layer.cpp +0 -40
  251. package/third-party/common/phonemis/src/phonemis/base/processor/trim_layer.h +0 -22
@@ -0,0 +1,2333 @@
1
+ /***************************************************************************
2
+ * Copyright (c) Johan Mabille, Sylvain Corlay, Wolf Vollprecht and *
3
+ * Martin Renou *
4
+ * Copyright (c) QuantStack *
5
+ * Copyright (c) Serge Guelton *
6
+ * *
7
+ * Distributed under the terms of the BSD 3-Clause License. *
8
+ * *
9
+ * The full license is in the file LICENSE, distributed with this software. *
10
+ ****************************************************************************/
11
+
12
+ #ifndef XSIMD_SSE2_HPP
13
+ #define XSIMD_SSE2_HPP
14
+
15
+ #include <complex>
16
+ #include <limits>
17
+ #include <type_traits>
18
+
19
+ #include "../types/xsimd_batch_constant.hpp"
20
+ #include "../types/xsimd_sse2_register.hpp"
21
+ #include "./utils/shifts.hpp"
22
+
23
+ namespace xsimd
24
+ {
25
+ template <typename T, class A, bool... Values>
26
+ struct batch_bool_constant;
27
+
28
+ template <class T_out, class T_in, class A>
29
+ XSIMD_INLINE batch<T_out, A> bitwise_cast(batch<T_in, A> const& x) noexcept;
30
+
31
+ template <typename T, class A, T... Values>
32
+ struct batch_constant;
33
+
34
+ namespace kernel
35
+ {
36
+ using namespace types;
37
+
38
+ namespace detail
39
+ {
40
+ constexpr uint32_t shuffle(uint32_t w, uint32_t x, uint32_t y, uint32_t z)
41
+ {
42
+ return (z << 6) | (y << 4) | (x << 2) | w;
43
+ }
44
+ constexpr uint32_t shuffle(uint32_t x, uint32_t y)
45
+ {
46
+ return (y << 1) | x;
47
+ }
48
+
49
+ constexpr uint32_t mod_shuffle(uint32_t w, uint32_t x, uint32_t y, uint32_t z)
50
+ {
51
+ return shuffle(w % 4, x % 4, y % 4, z % 4);
52
+ }
53
+
54
+ constexpr uint32_t mod_shuffle(uint32_t w, uint32_t x)
55
+ {
56
+ return shuffle(w % 2, x % 2);
57
+ }
58
+ }
59
+
60
+ // fwd
61
+ template <class A, class T, size_t I>
62
+ XSIMD_INLINE batch<T, A> insert(batch<T, A> const& self, T val, index<I>, requires_arch<common>) noexcept;
63
+ template <class A, typename T, typename ITy, ITy... Indices>
64
+ XSIMD_INLINE batch<T, A> shuffle(batch<T, A> const& x, batch<T, A> const& y, batch_constant<ITy, A, Indices...>, requires_arch<common>) noexcept;
65
+ template <class A, class T>
66
+ XSIMD_INLINE batch<T, A> avg(batch<T, A> const&, batch<T, A> const&, requires_arch<common>) noexcept;
67
+ template <class A, class T>
68
+ XSIMD_INLINE batch<T, A> avgr(batch<T, A> const&, batch<T, A> const&, requires_arch<common>) noexcept;
69
+
70
+ // abs
71
+ template <class A>
72
+ XSIMD_INLINE batch<double, A> abs(batch<double, A> const& self, requires_arch<sse2>) noexcept
73
+ {
74
+ __m128d sign_mask = _mm_set1_pd(-0.f); // -0.f = 1 << 31
75
+ return _mm_andnot_pd(sign_mask, self);
76
+ }
77
+ template <class A>
78
+ XSIMD_INLINE batch<float, A> abs(batch<float, A> const& self, requires_arch<sse2>) noexcept
79
+ {
80
+ __m128 sign_mask = _mm_set1_ps(-0.f); // -0.f = 1 << 31
81
+ return _mm_andnot_ps(sign_mask, self);
82
+ }
83
+
84
+ // add
85
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
86
+ XSIMD_INLINE batch<T, A> add(batch<T, A> const& self, batch<T, A> const& other, requires_arch<sse2>) noexcept
87
+ {
88
+ XSIMD_IF_CONSTEXPR(sizeof(T) == 1)
89
+ {
90
+ return _mm_add_epi8(self, other);
91
+ }
92
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 2)
93
+ {
94
+ return _mm_add_epi16(self, other);
95
+ }
96
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
97
+ {
98
+ return _mm_add_epi32(self, other);
99
+ }
100
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 8)
101
+ {
102
+ return _mm_add_epi64(self, other);
103
+ }
104
+ else
105
+ {
106
+ assert(false && "unsupported arch/op combination");
107
+ return {};
108
+ }
109
+ }
110
+
111
+ template <class A>
112
+ XSIMD_INLINE batch<float, A> add(batch<float, A> const& self, batch<float, A> const& other, requires_arch<sse2>) noexcept
113
+ {
114
+ return _mm_add_ps(self, other);
115
+ }
116
+
117
+ template <class A>
118
+ XSIMD_INLINE batch<double, A> add(batch<double, A> const& self, batch<double, A> const& other, requires_arch<sse2>) noexcept
119
+ {
120
+ return _mm_add_pd(self, other);
121
+ }
122
+
123
+ // all
124
+ template <class A>
125
+ XSIMD_INLINE bool all(batch_bool<float, A> const& self, requires_arch<sse2>) noexcept
126
+ {
127
+ return _mm_movemask_ps(self) == 0x0F;
128
+ }
129
+ template <class A>
130
+ XSIMD_INLINE bool all(batch_bool<double, A> const& self, requires_arch<sse2>) noexcept
131
+ {
132
+ return _mm_movemask_pd(self) == 0x03;
133
+ }
134
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
135
+ XSIMD_INLINE bool all(batch_bool<T, A> const& self, requires_arch<sse2>) noexcept
136
+ {
137
+ return _mm_movemask_epi8(self) == 0xFFFF;
138
+ }
139
+
140
+ // any
141
+ template <class A>
142
+ XSIMD_INLINE bool any(batch_bool<float, A> const& self, requires_arch<sse2>) noexcept
143
+ {
144
+ return _mm_movemask_ps(self) != 0;
145
+ }
146
+ template <class A>
147
+ XSIMD_INLINE bool any(batch_bool<double, A> const& self, requires_arch<sse2>) noexcept
148
+ {
149
+ return _mm_movemask_pd(self) != 0;
150
+ }
151
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
152
+ XSIMD_INLINE bool any(batch_bool<T, A> const& self, requires_arch<sse2>) noexcept
153
+ {
154
+ return _mm_movemask_epi8(self) != 0;
155
+ }
156
+
157
+ // avgr
158
+ template <class A, class T, class = std::enable_if_t<std::is_unsigned<T>::value>>
159
+ XSIMD_INLINE batch<T, A> avgr(batch<T, A> const& self, batch<T, A> const& other, requires_arch<sse2>) noexcept
160
+ {
161
+ XSIMD_IF_CONSTEXPR(sizeof(T) == 1)
162
+ {
163
+ return _mm_avg_epu8(self, other);
164
+ }
165
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 2)
166
+ {
167
+ return _mm_avg_epu16(self, other);
168
+ }
169
+ else
170
+ {
171
+ return avgr(self, other, common {});
172
+ }
173
+ }
174
+
175
+ // avg
176
+ template <class A, class T, class = std::enable_if_t<std::is_unsigned<T>::value>>
177
+ XSIMD_INLINE batch<T, A> avg(batch<T, A> const& self, batch<T, A> const& other, requires_arch<sse2>) noexcept
178
+ {
179
+ XSIMD_IF_CONSTEXPR(sizeof(T) == 1)
180
+ {
181
+ auto adj = ((self ^ other) << 7) >> 7;
182
+ return avgr(self, other, A {}) - adj;
183
+ }
184
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 2)
185
+ {
186
+ auto adj = ((self ^ other) << 15) >> 15;
187
+ return avgr(self, other, A {}) - adj;
188
+ }
189
+ else
190
+ {
191
+ return avg(self, other, common {});
192
+ }
193
+ }
194
+
195
+ // batch_bool_cast
196
+ template <class A, class T_out, class T_in>
197
+ 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<sse2>) noexcept
198
+ {
199
+ return { bitwise_cast<T_out>(batch<T_in, A>(self.data)).data };
200
+ }
201
+
202
+ // bitwise_and
203
+ template <class A>
204
+ XSIMD_INLINE batch<float, A> bitwise_and(batch<float, A> const& self, batch<float, A> const& other, requires_arch<sse2>) noexcept
205
+ {
206
+ return _mm_and_ps(self, other);
207
+ }
208
+ template <class A>
209
+ XSIMD_INLINE batch_bool<float, A> bitwise_and(batch_bool<float, A> const& self, batch_bool<float, A> const& other, requires_arch<sse2>) noexcept
210
+ {
211
+ return _mm_and_ps(self, other);
212
+ }
213
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
214
+ XSIMD_INLINE batch<T, A> bitwise_and(batch<T, A> const& self, batch<T, A> const& other, requires_arch<sse2>) noexcept
215
+ {
216
+ return _mm_and_si128(self, other);
217
+ }
218
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
219
+ XSIMD_INLINE batch_bool<T, A> bitwise_and(batch_bool<T, A> const& self, batch_bool<T, A> const& other, requires_arch<sse2>) noexcept
220
+ {
221
+ return _mm_and_si128(self, other);
222
+ }
223
+
224
+ template <class A>
225
+ batch<double, A> XSIMD_INLINE bitwise_and(batch<double, A> const& self, batch<double, A> const& other, requires_arch<sse2>) noexcept
226
+ {
227
+ return _mm_and_pd(self, other);
228
+ }
229
+
230
+ template <class A>
231
+ XSIMD_INLINE batch_bool<double, A> bitwise_and(batch_bool<double, A> const& self, batch_bool<double, A> const& other, requires_arch<sse2>) noexcept
232
+ {
233
+ return _mm_and_pd(self, other);
234
+ }
235
+
236
+ // bitwise_andnot
237
+ template <class A>
238
+ XSIMD_INLINE batch<float, A> bitwise_andnot(batch<float, A> const& self, batch<float, A> const& other, requires_arch<sse2>) noexcept
239
+ {
240
+ return _mm_andnot_ps(other, self);
241
+ }
242
+
243
+ template <class A>
244
+ XSIMD_INLINE batch_bool<float, A> bitwise_andnot(batch_bool<float, A> const& self, batch_bool<float, A> const& other, requires_arch<sse2>) noexcept
245
+ {
246
+ return _mm_andnot_ps(other, self);
247
+ }
248
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
249
+ XSIMD_INLINE batch<T, A> bitwise_andnot(batch<T, A> const& self, batch<T, A> const& other, requires_arch<sse2>) noexcept
250
+ {
251
+ return _mm_andnot_si128(other, self);
252
+ }
253
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
254
+ XSIMD_INLINE batch_bool<T, A> bitwise_andnot(batch_bool<T, A> const& self, batch_bool<T, A> const& other, requires_arch<sse2>) noexcept
255
+ {
256
+ return _mm_andnot_si128(other, self);
257
+ }
258
+
259
+ template <class A>
260
+ XSIMD_INLINE batch<double, A> bitwise_andnot(batch<double, A> const& self, batch<double, A> const& other, requires_arch<sse2>) noexcept
261
+ {
262
+ return _mm_andnot_pd(other, self);
263
+ }
264
+
265
+ template <class A>
266
+ XSIMD_INLINE batch_bool<double, A> bitwise_andnot(batch_bool<double, A> const& self, batch_bool<double, A> const& other, requires_arch<sse2>) noexcept
267
+ {
268
+ return _mm_andnot_pd(other, self);
269
+ }
270
+
271
+ // bitwise_lshift
272
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
273
+ XSIMD_INLINE batch<T, A> bitwise_lshift(batch<T, A> const& self, int32_t other, requires_arch<sse2>) noexcept
274
+ {
275
+ XSIMD_IF_CONSTEXPR(sizeof(T) == 1)
276
+ {
277
+ return _mm_and_si128(_mm_set1_epi8(0xFF << other), _mm_slli_epi32(self, other));
278
+ }
279
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 2)
280
+ {
281
+ return _mm_slli_epi16(self, other);
282
+ }
283
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
284
+ {
285
+ return _mm_slli_epi32(self, other);
286
+ }
287
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 8)
288
+ {
289
+ return _mm_slli_epi64(self, other);
290
+ }
291
+ else
292
+ {
293
+ assert(false && "unsupported arch/op combination");
294
+ return {};
295
+ }
296
+ }
297
+ template <size_t shift, class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
298
+ XSIMD_INLINE batch<T, A> bitwise_lshift(batch<T, A> const& self, requires_arch<sse2>) noexcept
299
+ {
300
+ constexpr auto bits = std::numeric_limits<T>::digits + std::numeric_limits<T>::is_signed;
301
+ static_assert(shift < bits, "Count must be less than the number of bits in T");
302
+ XSIMD_IF_CONSTEXPR(shift == 0)
303
+ {
304
+ return self;
305
+ }
306
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 1)
307
+ {
308
+ // 8-bit left shift via 16-bit shift + mask
309
+ __m128i shifted = _mm_slli_epi16(self, static_cast<int>(shift));
310
+ // TODO(C++17): without `if constexpr` we must ensure the compile-time shift does not overflow
311
+ constexpr uint8_t mask8 = static_cast<uint8_t>(sizeof(T) == 1 ? (~0u << shift) : 0);
312
+ const __m128i mask = _mm_set1_epi8(mask8);
313
+ return _mm_and_si128(shifted, mask);
314
+ }
315
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 2)
316
+ {
317
+ return _mm_slli_epi16(self, static_cast<int>(shift));
318
+ }
319
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
320
+ {
321
+ return _mm_slli_epi32(self, static_cast<int>(shift));
322
+ }
323
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 8)
324
+ {
325
+ return _mm_slli_epi64(self, static_cast<int>(shift));
326
+ }
327
+ return bitwise_lshift<shift>(self, common {});
328
+ }
329
+
330
+ // bitwise_lshift multiple (constant)
331
+ // Missing implementations are dispacthed to the `batch` overload in xsimd_api.
332
+ template <class A, class T, T... Vs, detail::enable_sized_integral_t<T, 2> = 0>
333
+ XSIMD_INLINE batch<T, A> bitwise_lshift(
334
+ batch<T, A> const& self, batch_constant<T, A, Vs...> shifts, requires_arch<sse2> req) noexcept
335
+ {
336
+ XSIMD_IF_CONSTEXPR(utils::all_equals(shifts))
337
+ {
338
+ return bitwise_lshift<shifts.get(0), A>(self, req);
339
+ }
340
+ constexpr auto mults = batch_constant<T, A, static_cast<T>(1u << Vs)...>();
341
+ return _mm_mullo_epi16(self, mults.as_batch());
342
+ }
343
+
344
+ template <class A, class T, T... Vs, detail::enable_sized_integral_t<T, 1> = 0>
345
+ XSIMD_INLINE batch<T, A> bitwise_lshift(
346
+ batch<T, A> const& self, batch_constant<T, A, Vs...> shifts, requires_arch<sse2> req) noexcept
347
+ {
348
+ using uint_t = std::make_unsigned_t<T>;
349
+
350
+ XSIMD_IF_CONSTEXPR(utils::all_equals(shifts))
351
+ {
352
+ return bitwise_lshift<shifts.get(0), A>(self, req);
353
+ }
354
+ return bitwise_cast<T>(
355
+ utils::bitwise_lshift_as_twice_larger<uint_t>(
356
+ bitwise_cast<uint_t>(self),
357
+ batch_constant<uint_t, A, static_cast<uint_t>(Vs)...> {}));
358
+ }
359
+
360
+ // bitwise_not
361
+ template <class A>
362
+ XSIMD_INLINE batch<float, A> bitwise_not(batch<float, A> const& self, requires_arch<sse2>) noexcept
363
+ {
364
+ return _mm_xor_ps(self, _mm_castsi128_ps(_mm_set1_epi32(-1)));
365
+ }
366
+ template <class A>
367
+ XSIMD_INLINE batch_bool<float, A> bitwise_not(batch_bool<float, A> const& self, requires_arch<sse2>) noexcept
368
+ {
369
+ return _mm_xor_ps(self, _mm_castsi128_ps(_mm_set1_epi32(-1)));
370
+ }
371
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
372
+ XSIMD_INLINE batch<T, A> bitwise_not(batch<T, A> const& self, requires_arch<sse2>) noexcept
373
+ {
374
+ return _mm_xor_si128(self, _mm_set1_epi32(-1));
375
+ }
376
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
377
+ XSIMD_INLINE batch_bool<T, A> bitwise_not(batch_bool<T, A> const& self, requires_arch<sse2>) noexcept
378
+ {
379
+ return _mm_xor_si128(self, _mm_set1_epi32(-1));
380
+ }
381
+ template <class A>
382
+ XSIMD_INLINE batch<double, A> bitwise_not(batch<double, A> const& self, requires_arch<sse2>) noexcept
383
+ {
384
+ return _mm_xor_pd(self, _mm_castsi128_pd(_mm_set1_epi32(-1)));
385
+ }
386
+ template <class A>
387
+ XSIMD_INLINE batch_bool<double, A> bitwise_not(batch_bool<double, A> const& self, requires_arch<sse2>) noexcept
388
+ {
389
+ return _mm_xor_pd(self, _mm_castsi128_pd(_mm_set1_epi32(-1)));
390
+ }
391
+
392
+ // bitwise_or
393
+ template <class A>
394
+ XSIMD_INLINE batch<float, A> bitwise_or(batch<float, A> const& self, batch<float, A> const& other, requires_arch<sse2>) noexcept
395
+ {
396
+ return _mm_or_ps(self, other);
397
+ }
398
+ template <class A>
399
+ XSIMD_INLINE batch_bool<float, A> bitwise_or(batch_bool<float, A> const& self, batch_bool<float, A> const& other, requires_arch<sse2>) noexcept
400
+ {
401
+ return _mm_or_ps(self, other);
402
+ }
403
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
404
+ XSIMD_INLINE batch<T, A> bitwise_or(batch<T, A> const& self, batch<T, A> const& other, requires_arch<sse2>) noexcept
405
+ {
406
+ return _mm_or_si128(self, other);
407
+ }
408
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
409
+ XSIMD_INLINE batch_bool<T, A> bitwise_or(batch_bool<T, A> const& self, batch_bool<T, A> const& other, requires_arch<sse2>) noexcept
410
+ {
411
+ return _mm_or_si128(self, other);
412
+ }
413
+
414
+ template <class A>
415
+ XSIMD_INLINE batch<double, A> bitwise_or(batch<double, A> const& self, batch<double, A> const& other, requires_arch<sse2>) noexcept
416
+ {
417
+ return _mm_or_pd(self, other);
418
+ }
419
+
420
+ template <class A>
421
+ XSIMD_INLINE batch_bool<double, A> bitwise_or(batch_bool<double, A> const& self, batch_bool<double, A> const& other, requires_arch<sse2>) noexcept
422
+ {
423
+ return _mm_or_pd(self, other);
424
+ }
425
+
426
+ // bitwise_rshift
427
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
428
+ XSIMD_INLINE batch<T, A> bitwise_rshift(batch<T, A> const& self, int32_t other, requires_arch<sse2>) noexcept
429
+ {
430
+ if (std::is_signed<T>::value)
431
+ {
432
+ XSIMD_IF_CONSTEXPR(sizeof(T) == 1)
433
+ {
434
+ __m128i sign_mask = _mm_set1_epi16((0xFF00 >> other) & 0x00FF);
435
+ __m128i cmp_is_negative = _mm_cmpgt_epi8(_mm_setzero_si128(), self);
436
+ __m128i res = _mm_srai_epi16(self, other);
437
+ return _mm_or_si128(_mm_and_si128(sign_mask, cmp_is_negative), _mm_andnot_si128(sign_mask, res));
438
+ }
439
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 2)
440
+ {
441
+ return _mm_srai_epi16(self, other);
442
+ }
443
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
444
+ {
445
+ return _mm_srai_epi32(self, other);
446
+ }
447
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 8)
448
+ {
449
+ // from https://github.com/samyvilar/vect/blob/master/vect_128.h
450
+ return _mm_or_si128(
451
+ _mm_srli_epi64(self, other),
452
+ _mm_slli_epi64(
453
+ _mm_srai_epi32(_mm_shuffle_epi32(self, _MM_SHUFFLE(3, 3, 1, 1)), 32),
454
+ 64 - other));
455
+ }
456
+ else
457
+ {
458
+ assert(false && "unsupported arch/op combination");
459
+ return {};
460
+ }
461
+ }
462
+ else
463
+ {
464
+ XSIMD_IF_CONSTEXPR(sizeof(T) == 1)
465
+ {
466
+ return _mm_and_si128(_mm_set1_epi8(0xFF >> other), _mm_srli_epi32(self, other));
467
+ }
468
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 2)
469
+ {
470
+ return _mm_srli_epi16(self, other);
471
+ }
472
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
473
+ {
474
+ return _mm_srli_epi32(self, other);
475
+ }
476
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 8)
477
+ {
478
+ return _mm_srli_epi64(self, other);
479
+ }
480
+ else
481
+ {
482
+ assert(false && "unsupported arch/op combination");
483
+ return {};
484
+ }
485
+ }
486
+ }
487
+ template <size_t shift, class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
488
+ XSIMD_INLINE batch<T, A> bitwise_rshift(batch<T, A> const& self, requires_arch<sse2>) noexcept
489
+ {
490
+ constexpr auto bits = std::numeric_limits<T>::digits + std::numeric_limits<T>::is_signed;
491
+ static_assert(shift < bits,
492
+ "Shift must be less than the number of value bits in the type");
493
+
494
+ XSIMD_IF_CONSTEXPR(shift == 0)
495
+ {
496
+ return self;
497
+ }
498
+
499
+ XSIMD_IF_CONSTEXPR(std::is_signed<T>::value)
500
+ {
501
+ XSIMD_IF_CONSTEXPR(sizeof(T) == 1)
502
+ {
503
+ // 8-bit arithmetic right shift via 16-bit shift + sign-extension handling.
504
+ __m128i shifted = _mm_srai_epi16(self, static_cast<int>(shift));
505
+ __m128i sign_mask = _mm_set1_epi16(static_cast<short>(0xFF00 >> shift));
506
+ __m128i cmp_negative = _mm_cmpgt_epi8(_mm_setzero_si128(), self);
507
+ return _mm_or_si128(_mm_and_si128(sign_mask, cmp_negative),
508
+ _mm_andnot_si128(sign_mask, shifted));
509
+ }
510
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 2)
511
+ {
512
+ return _mm_srai_epi16(self, static_cast<int>(shift));
513
+ }
514
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
515
+ {
516
+ return _mm_srai_epi32(self, static_cast<int>(shift));
517
+ }
518
+ // No 64-bit arithmetic right shift in SSE2; fall back
519
+ return bitwise_rshift<shift>(self, common {});
520
+ }
521
+ else // unsigned / logical right shift
522
+ {
523
+ XSIMD_IF_CONSTEXPR(sizeof(T) == 1)
524
+ {
525
+ // 8-bit left shift via 16-bit shift + mask
526
+ __m128i shifted = _mm_srli_epi16(self, static_cast<int>(shift));
527
+ // TODO(C++17): without `if constexpr` we must ensure the compile-time shift does not overflow
528
+ constexpr uint8_t mask8 = static_cast<uint8_t>(sizeof(T) == 1 ? ((1u << shift) - 1u) : 0);
529
+ const __m128i mask = _mm_set1_epi8(mask8);
530
+ return _mm_and_si128(shifted, mask);
531
+ }
532
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 2)
533
+ {
534
+ return _mm_srli_epi16(self, static_cast<int>(shift));
535
+ }
536
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
537
+ {
538
+ return _mm_srli_epi32(self, static_cast<int>(shift));
539
+ }
540
+ else // sizeof(T) == 8
541
+ {
542
+ return _mm_srli_epi64(self, static_cast<int>(shift));
543
+ }
544
+ }
545
+ }
546
+
547
+ // bitwise_xor
548
+ template <class A>
549
+ XSIMD_INLINE batch<float, A> bitwise_xor(batch<float, A> const& self, batch<float, A> const& other, requires_arch<sse2>) noexcept
550
+ {
551
+ return _mm_xor_ps(self, other);
552
+ }
553
+ template <class A>
554
+ XSIMD_INLINE batch_bool<float, A> bitwise_xor(batch_bool<float, A> const& self, batch_bool<float, A> const& other, requires_arch<sse2>) noexcept
555
+ {
556
+ return _mm_xor_ps(self, other);
557
+ }
558
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
559
+ XSIMD_INLINE batch<T, A> bitwise_xor(batch<T, A> const& self, batch<T, A> const& other, requires_arch<sse2>) noexcept
560
+ {
561
+ return _mm_xor_si128(self, other);
562
+ }
563
+ template <class A>
564
+ XSIMD_INLINE batch<double, A> bitwise_xor(batch<double, A> const& self, batch<double, A> const& other, requires_arch<sse2>) noexcept
565
+ {
566
+ return _mm_xor_pd(self, other);
567
+ }
568
+ template <class A>
569
+ XSIMD_INLINE batch_bool<double, A> bitwise_xor(batch_bool<double, A> const& self, batch_bool<double, A> const& other, requires_arch<sse2>) noexcept
570
+ {
571
+ return _mm_xor_pd(self, other);
572
+ }
573
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
574
+ XSIMD_INLINE batch<T, A> bitwise_xor(batch_bool<T, A> const& self, batch_bool<T, A> const& other, requires_arch<sse2>) noexcept
575
+ {
576
+ return _mm_xor_si128(self, other);
577
+ }
578
+
579
+ // bitwise_cast
580
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
581
+ XSIMD_INLINE batch<float, A> bitwise_cast(batch<T, A> const& self, batch<float, A> const&, requires_arch<sse2>) noexcept
582
+ {
583
+ return _mm_castsi128_ps(self);
584
+ }
585
+ template <class A, class T, class Tp, class = std::enable_if_t<std::is_integral<std::common_type_t<T, Tp>>::value>>
586
+ XSIMD_INLINE batch<Tp, A> bitwise_cast(batch<T, A> const& self, batch<Tp, A> const&, requires_arch<sse2>) noexcept
587
+ {
588
+ return batch<Tp, A>(self.data);
589
+ }
590
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
591
+ XSIMD_INLINE batch<T, A> bitwise_cast(batch<float, A> const& self, batch<T, A> const&, requires_arch<sse2>) noexcept
592
+ {
593
+ return _mm_castps_si128(self);
594
+ }
595
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
596
+ XSIMD_INLINE batch<double, A> bitwise_cast(batch<T, A> const& self, batch<double, A> const&, requires_arch<sse2>) noexcept
597
+ {
598
+ return _mm_castsi128_pd(self);
599
+ }
600
+ template <class A>
601
+ XSIMD_INLINE batch<double, A> bitwise_cast(batch<float, A> const& self, batch<double, A> const&, requires_arch<sse2>) noexcept
602
+ {
603
+ return _mm_castps_pd(self);
604
+ }
605
+ template <class A>
606
+ XSIMD_INLINE batch<float, A> bitwise_cast(batch<double, A> const& self, batch<float, A> const&, requires_arch<sse2>) noexcept
607
+ {
608
+ return _mm_castpd_ps(self);
609
+ }
610
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
611
+ XSIMD_INLINE batch<T, A> bitwise_cast(batch<double, A> const& self, batch<T, A> const&, requires_arch<sse2>) noexcept
612
+ {
613
+ return _mm_castpd_si128(self);
614
+ }
615
+
616
+ // broadcast
617
+ template <class A>
618
+ batch<float, A> XSIMD_INLINE broadcast(float val, requires_arch<sse2>) noexcept
619
+ {
620
+ return _mm_set1_ps(val);
621
+ }
622
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
623
+ XSIMD_INLINE batch<T, A> broadcast(T val, requires_arch<sse2>) noexcept
624
+ {
625
+ XSIMD_IF_CONSTEXPR(sizeof(T) == 1)
626
+ {
627
+ return _mm_set1_epi8(val);
628
+ }
629
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 2)
630
+ {
631
+ return _mm_set1_epi16(val);
632
+ }
633
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
634
+ {
635
+ return _mm_set1_epi32(val);
636
+ }
637
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 8)
638
+ {
639
+ return _mm_set1_epi64x(val);
640
+ }
641
+ else
642
+ {
643
+ assert(false && "unsupported arch/op combination");
644
+ return {};
645
+ }
646
+ }
647
+ template <class A>
648
+ XSIMD_INLINE batch<double, A> broadcast(double val, requires_arch<sse2>) noexcept
649
+ {
650
+ return _mm_set1_pd(val);
651
+ }
652
+
653
+ // store_complex
654
+ namespace detail
655
+ {
656
+ // Override these methods in SSE-based archs, no need to override store_aligned / store_unaligned
657
+ // complex_low
658
+ template <class A>
659
+ XSIMD_INLINE batch<float, A> complex_low(batch<std::complex<float>, A> const& self, requires_arch<sse2>) noexcept
660
+ {
661
+ return _mm_unpacklo_ps(self.real(), self.imag());
662
+ }
663
+ // complex_high
664
+ template <class A>
665
+ XSIMD_INLINE batch<float, A> complex_high(batch<std::complex<float>, A> const& self, requires_arch<sse2>) noexcept
666
+ {
667
+ return _mm_unpackhi_ps(self.real(), self.imag());
668
+ }
669
+ template <class A>
670
+ XSIMD_INLINE batch<double, A> complex_low(batch<std::complex<double>, A> const& self, requires_arch<sse2>) noexcept
671
+ {
672
+ return _mm_unpacklo_pd(self.real(), self.imag());
673
+ }
674
+ template <class A>
675
+ XSIMD_INLINE batch<double, A> complex_high(batch<std::complex<double>, A> const& self, requires_arch<sse2>) noexcept
676
+ {
677
+ return _mm_unpackhi_pd(self.real(), self.imag());
678
+ }
679
+ }
680
+
681
+ // decr_if
682
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
683
+ XSIMD_INLINE batch<T, A> decr_if(batch<T, A> const& self, batch_bool<T, A> const& mask, requires_arch<sse2>) noexcept
684
+ {
685
+ return self + batch<T, A>(mask.data);
686
+ }
687
+
688
+ // div
689
+ template <class A>
690
+ XSIMD_INLINE batch<float, A> div(batch<float, A> const& self, batch<float, A> const& other, requires_arch<sse2>) noexcept
691
+ {
692
+ return _mm_div_ps(self, other);
693
+ }
694
+ template <class A>
695
+ XSIMD_INLINE batch<double, A> div(batch<double, A> const& self, batch<double, A> const& other, requires_arch<sse2>) noexcept
696
+ {
697
+ return _mm_div_pd(self, other);
698
+ }
699
+
700
+ // fast_cast
701
+ namespace detail
702
+ {
703
+ template <class A>
704
+ XSIMD_INLINE batch<float, A> fast_cast(batch<int32_t, A> const& self, batch<float, A> const&, requires_arch<sse2>) noexcept
705
+ {
706
+ return _mm_cvtepi32_ps(self);
707
+ }
708
+
709
+ template <class A>
710
+ XSIMD_INLINE batch<double, A> fast_cast(batch<uint64_t, A> const& x, batch<double, A> const&, requires_arch<sse2>) noexcept
711
+ {
712
+ // from https://stackoverflow.com/questions/41144668/how-to-efficiently-perform-double-int64-conversions-with-sse-avx
713
+ // adapted to sse2
714
+ __m128i xH = _mm_srli_epi64(x, 32);
715
+ xH = _mm_or_si128(xH, _mm_castpd_si128(_mm_set1_pd(19342813113834066795298816.))); // 2^84
716
+ __m128i mask = _mm_setr_epi16(0xFFFF, 0xFFFF, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0x0000, 0x0000);
717
+ __m128i xL = _mm_or_si128(_mm_and_si128(mask, x), _mm_andnot_si128(mask, _mm_castpd_si128(_mm_set1_pd(0x0010000000000000)))); // 2^52
718
+ __m128d f = _mm_sub_pd(_mm_castsi128_pd(xH), _mm_set1_pd(19342813118337666422669312.)); // 2^84 + 2^52
719
+ detail::reassociation_barrier(f, "prevent (xH-C)+xL -> xH+(xL-C)");
720
+ return _mm_add_pd(f, _mm_castsi128_pd(xL));
721
+ }
722
+
723
+ template <class A>
724
+ XSIMD_INLINE batch<double, A> fast_cast(batch<int64_t, A> const& x, batch<double, A> const&, requires_arch<sse2>) noexcept
725
+ {
726
+ // from https://stackoverflow.com/questions/41144668/how-to-efficiently-perform-double-int64-conversions-with-sse-avx
727
+ // adapted to sse2
728
+ __m128i xH = _mm_srai_epi32(x, 16);
729
+ xH = _mm_and_si128(xH, _mm_setr_epi16(0x0000, 0x0000, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0xFFFF, 0xFFFF));
730
+ xH = _mm_add_epi64(xH, _mm_castpd_si128(_mm_set1_pd(442721857769029238784.))); // 3*2^67
731
+ __m128i mask = _mm_setr_epi16(0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0x0000);
732
+ __m128i xL = _mm_or_si128(_mm_and_si128(mask, x), _mm_andnot_si128(mask, _mm_castpd_si128(_mm_set1_pd(0x0010000000000000)))); // 2^52
733
+ __m128d f = _mm_sub_pd(_mm_castsi128_pd(xH), _mm_set1_pd(442726361368656609280.)); // 3*2^67 + 2^52
734
+ detail::reassociation_barrier(f, "prevent (xH-C)+xL -> xH+(xL-C)");
735
+ return _mm_add_pd(f, _mm_castsi128_pd(xL));
736
+ }
737
+
738
+ template <class A>
739
+ XSIMD_INLINE batch<int32_t, A> fast_cast(batch<float, A> const& self, batch<int32_t, A> const&, requires_arch<sse2>) noexcept
740
+ {
741
+ return _mm_cvttps_epi32(self);
742
+ }
743
+ }
744
+
745
+ // eq
746
+ template <class A>
747
+ XSIMD_INLINE batch_bool<float, A> eq(batch<float, A> const& self, batch<float, A> const& other, requires_arch<sse2>) noexcept
748
+ {
749
+ return _mm_cmpeq_ps(self, other);
750
+ }
751
+ template <class A>
752
+ XSIMD_INLINE batch_bool<float, A> eq(batch_bool<float, A> const& self, batch_bool<float, A> const& other, requires_arch<sse2>) noexcept
753
+ {
754
+ return _mm_castsi128_ps(_mm_cmpeq_epi32(_mm_castps_si128(self), _mm_castps_si128(other)));
755
+ }
756
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
757
+ XSIMD_INLINE batch_bool<T, A> eq(batch<T, A> const& self, batch<T, A> const& other, requires_arch<sse2>) noexcept
758
+ {
759
+ XSIMD_IF_CONSTEXPR(sizeof(T) == 1)
760
+ {
761
+ return _mm_cmpeq_epi8(self, other);
762
+ }
763
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 2)
764
+ {
765
+ return _mm_cmpeq_epi16(self, other);
766
+ }
767
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
768
+ {
769
+ return _mm_cmpeq_epi32(self, other);
770
+ }
771
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 8)
772
+ {
773
+ __m128i tmp1 = _mm_cmpeq_epi32(self, other);
774
+ __m128i tmp2 = _mm_shuffle_epi32(tmp1, 0xB1);
775
+ __m128i tmp3 = _mm_and_si128(tmp1, tmp2);
776
+ __m128i tmp4 = _mm_srai_epi32(tmp3, 31);
777
+ return _mm_shuffle_epi32(tmp4, 0xF5);
778
+ }
779
+ else
780
+ {
781
+ assert(false && "unsupported arch/op combination");
782
+ return {};
783
+ }
784
+ }
785
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
786
+ XSIMD_INLINE batch_bool<T, A> eq(batch_bool<T, A> const& self, batch_bool<T, A> const& other, requires_arch<sse2>) noexcept
787
+ {
788
+ return ~(self != other);
789
+ }
790
+ template <class A>
791
+ XSIMD_INLINE batch_bool<double, A> eq(batch<double, A> const& self, batch<double, A> const& other, requires_arch<sse2>) noexcept
792
+ {
793
+ return _mm_cmpeq_pd(self, other);
794
+ }
795
+ template <class A>
796
+ XSIMD_INLINE batch_bool<double, A> eq(batch_bool<double, A> const& self, batch_bool<double, A> const& other, requires_arch<sse2>) noexcept
797
+ {
798
+ return _mm_castsi128_pd(_mm_cmpeq_epi32(_mm_castpd_si128(self), _mm_castpd_si128(other)));
799
+ }
800
+
801
+ // first
802
+ template <class A>
803
+ XSIMD_INLINE float first(batch<float, A> const& self, requires_arch<sse2>) noexcept
804
+ {
805
+ return _mm_cvtss_f32(self);
806
+ }
807
+
808
+ template <class A>
809
+ XSIMD_INLINE double first(batch<double, A> const& self, requires_arch<sse2>) noexcept
810
+ {
811
+ return _mm_cvtsd_f64(self);
812
+ }
813
+
814
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
815
+ XSIMD_INLINE T first(batch<T, A> const& self, requires_arch<sse2>) noexcept
816
+ {
817
+ XSIMD_IF_CONSTEXPR(sizeof(T) == 1)
818
+ {
819
+ return static_cast<T>(_mm_cvtsi128_si32(self) & 0xFF);
820
+ }
821
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 2)
822
+ {
823
+ return static_cast<T>(_mm_cvtsi128_si32(self) & 0xFFFF);
824
+ }
825
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
826
+ {
827
+ return static_cast<T>(_mm_cvtsi128_si32(self));
828
+ }
829
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 8)
830
+ {
831
+ #if defined(__x86_64__)
832
+ return static_cast<T>(_mm_cvtsi128_si64(self));
833
+ #else
834
+ __m128i m;
835
+ _mm_storel_epi64(&m, self);
836
+ int64_t i;
837
+ std::memcpy(&i, &m, sizeof(i));
838
+ return i;
839
+ #endif
840
+ }
841
+ else
842
+ {
843
+ assert(false && "unsupported arch/op combination");
844
+ return {};
845
+ }
846
+ }
847
+
848
+ // from_mask
849
+ template <class A>
850
+ XSIMD_INLINE batch_bool<float, A> from_mask(batch_bool<float, A> const&, uint64_t mask, requires_arch<sse2>) noexcept
851
+ {
852
+ alignas(A::alignment()) static const uint32_t lut[][4] = {
853
+ { 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
854
+ { 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000 },
855
+ { 0x00000000, 0xFFFFFFFF, 0x00000000, 0x00000000 },
856
+ { 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000 },
857
+ { 0x00000000, 0x00000000, 0xFFFFFFFF, 0x00000000 },
858
+ { 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000 },
859
+ { 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000 },
860
+ { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000 },
861
+ { 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF },
862
+ { 0xFFFFFFFF, 0x00000000, 0x00000000, 0xFFFFFFFF },
863
+ { 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF },
864
+ { 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF },
865
+ { 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF },
866
+ { 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF },
867
+ { 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF },
868
+ { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF },
869
+ };
870
+ assert(!(mask & ~0xFul) && "inbound mask");
871
+ return _mm_castsi128_ps(_mm_load_si128((const __m128i*)lut[mask]));
872
+ }
873
+ template <class A>
874
+ XSIMD_INLINE batch_bool<double, A> from_mask(batch_bool<double, A> const&, uint64_t mask, requires_arch<sse2>) noexcept
875
+ {
876
+ alignas(A::alignment()) static const uint64_t lut[][4] = {
877
+ { 0x0000000000000000ul, 0x0000000000000000ul },
878
+ { 0xFFFFFFFFFFFFFFFFul, 0x0000000000000000ul },
879
+ { 0x0000000000000000ul, 0xFFFFFFFFFFFFFFFFul },
880
+ { 0xFFFFFFFFFFFFFFFFul, 0xFFFFFFFFFFFFFFFFul },
881
+ };
882
+ assert(!(mask & ~0x3ul) && "inbound mask");
883
+ return _mm_castsi128_pd(_mm_load_si128((const __m128i*)lut[mask]));
884
+ }
885
+ template <class T, class A, class = std::enable_if_t<std::is_integral<T>::value>>
886
+ XSIMD_INLINE batch_bool<T, A> from_mask(batch_bool<T, A> const&, uint64_t mask, requires_arch<sse2>) noexcept
887
+ {
888
+ alignas(A::alignment()) static const uint64_t lut64[] = {
889
+ 0x0000000000000000,
890
+ 0x000000000000FFFF,
891
+ 0x00000000FFFF0000,
892
+ 0x00000000FFFFFFFF,
893
+ 0x0000FFFF00000000,
894
+ 0x0000FFFF0000FFFF,
895
+ 0x0000FFFFFFFF0000,
896
+ 0x0000FFFFFFFFFFFF,
897
+ 0xFFFF000000000000,
898
+ 0xFFFF00000000FFFF,
899
+ 0xFFFF0000FFFF0000,
900
+ 0xFFFF0000FFFFFFFF,
901
+ 0xFFFFFFFF00000000,
902
+ 0xFFFFFFFF0000FFFF,
903
+ 0xFFFFFFFFFFFF0000,
904
+ 0xFFFFFFFFFFFFFFFF,
905
+ };
906
+ alignas(A::alignment()) static const uint32_t lut32[] = {
907
+ 0x00000000,
908
+ 0x000000FF,
909
+ 0x0000FF00,
910
+ 0x0000FFFF,
911
+ 0x00FF0000,
912
+ 0x00FF00FF,
913
+ 0x00FFFF00,
914
+ 0x00FFFFFF,
915
+ 0xFF000000,
916
+ 0xFF0000FF,
917
+ 0xFF00FF00,
918
+ 0xFF00FFFF,
919
+ 0xFFFF0000,
920
+ 0xFFFF00FF,
921
+ 0xFFFFFF00,
922
+ 0xFFFFFFFF,
923
+ };
924
+ XSIMD_IF_CONSTEXPR(sizeof(T) == 1)
925
+ {
926
+ assert(!(mask & ~0xFFFF) && "inbound mask");
927
+ return _mm_setr_epi32(lut32[mask & 0xF], lut32[(mask >> 4) & 0xF], lut32[(mask >> 8) & 0xF], lut32[mask >> 12]);
928
+ }
929
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 2)
930
+ {
931
+ assert(!(mask & ~0xFF) && "inbound mask");
932
+ return _mm_set_epi64x(lut64[mask >> 4], lut64[mask & 0xF]);
933
+ }
934
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
935
+ {
936
+ return _mm_castps_si128(from_mask(batch_bool<float, A> {}, mask, sse2 {}));
937
+ }
938
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 8)
939
+ {
940
+ return _mm_castpd_si128(from_mask(batch_bool<double, A> {}, mask, sse2 {}));
941
+ }
942
+ }
943
+
944
+ // ge
945
+ template <class A>
946
+ XSIMD_INLINE batch_bool<float, A> ge(batch<float, A> const& self, batch<float, A> const& other, requires_arch<sse2>) noexcept
947
+ {
948
+ return _mm_cmpge_ps(self, other);
949
+ }
950
+ template <class A>
951
+ XSIMD_INLINE batch_bool<double, A> ge(batch<double, A> const& self, batch<double, A> const& other, requires_arch<sse2>) noexcept
952
+ {
953
+ return _mm_cmpge_pd(self, other);
954
+ }
955
+
956
+ // gt
957
+ template <class A>
958
+ XSIMD_INLINE batch_bool<float, A> gt(batch<float, A> const& self, batch<float, A> const& other, requires_arch<sse2>) noexcept
959
+ {
960
+ return _mm_cmpgt_ps(self, other);
961
+ }
962
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
963
+ XSIMD_INLINE batch_bool<T, A> gt(batch<T, A> const& self, batch<T, A> const& other, requires_arch<sse2>) noexcept
964
+ {
965
+ if (std::is_signed<T>::value)
966
+ {
967
+ XSIMD_IF_CONSTEXPR(sizeof(T) == 1)
968
+ {
969
+ return _mm_cmpgt_epi8(self, other);
970
+ }
971
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 2)
972
+ {
973
+ return _mm_cmpgt_epi16(self, other);
974
+ }
975
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
976
+ {
977
+ return _mm_cmpgt_epi32(self, other);
978
+ }
979
+ else
980
+ {
981
+ return gt(self, other, common {});
982
+ }
983
+ }
984
+ else
985
+ {
986
+ return gt(self, other, common {});
987
+ }
988
+ }
989
+
990
+ template <class A>
991
+ XSIMD_INLINE batch_bool<double, A> gt(batch<double, A> const& self, batch<double, A> const& other, requires_arch<sse2>) noexcept
992
+ {
993
+ return _mm_cmpgt_pd(self, other);
994
+ }
995
+
996
+ // haddp
997
+ template <class A>
998
+ XSIMD_INLINE batch<float, A> haddp(batch<float, A> const* row, requires_arch<sse2>) noexcept
999
+ {
1000
+ __m128 tmp0 = _mm_unpacklo_ps(row[0], row[1]);
1001
+ __m128 tmp1 = _mm_unpackhi_ps(row[0], row[1]);
1002
+ __m128 tmp2 = _mm_unpackhi_ps(row[2], row[3]);
1003
+ tmp0 = _mm_add_ps(tmp0, tmp1);
1004
+ tmp1 = _mm_unpacklo_ps(row[2], row[3]);
1005
+ tmp1 = _mm_add_ps(tmp1, tmp2);
1006
+ tmp2 = _mm_movehl_ps(tmp1, tmp0);
1007
+ tmp0 = _mm_movelh_ps(tmp0, tmp1);
1008
+ return _mm_add_ps(tmp0, tmp2);
1009
+ }
1010
+ template <class A>
1011
+ XSIMD_INLINE batch<double, A> haddp(batch<double, A> const* row, requires_arch<sse2>) noexcept
1012
+ {
1013
+ return _mm_add_pd(_mm_unpacklo_pd(row[0], row[1]),
1014
+ _mm_unpackhi_pd(row[0], row[1]));
1015
+ }
1016
+
1017
+ // incr_if
1018
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
1019
+ XSIMD_INLINE batch<T, A> incr_if(batch<T, A> const& self, batch_bool<T, A> const& mask, requires_arch<sse2>) noexcept
1020
+ {
1021
+ return self - batch<T, A>(mask.data);
1022
+ }
1023
+
1024
+ // insert
1025
+ template <class A, class T, size_t I, class = std::enable_if_t<std::is_integral<T>::value>>
1026
+ XSIMD_INLINE batch<T, A> insert(batch<T, A> const& self, T val, index<I> pos, requires_arch<sse2>) noexcept
1027
+ {
1028
+ XSIMD_IF_CONSTEXPR(sizeof(T) == 2)
1029
+ {
1030
+ return _mm_insert_epi16(self, val, I);
1031
+ }
1032
+ else
1033
+ {
1034
+ return insert(self, val, pos, common {});
1035
+ }
1036
+ }
1037
+
1038
+ // isnan
1039
+ template <class A>
1040
+ XSIMD_INLINE batch_bool<float, A> isnan(batch<float, A> const& self, requires_arch<sse2>) noexcept
1041
+ {
1042
+ return _mm_cmpunord_ps(self, self);
1043
+ }
1044
+ template <class A>
1045
+ XSIMD_INLINE batch_bool<double, A> isnan(batch<double, A> const& self, requires_arch<sse2>) noexcept
1046
+ {
1047
+ return _mm_cmpunord_pd(self, self);
1048
+ }
1049
+
1050
+ // load_aligned
1051
+ template <class A>
1052
+ XSIMD_INLINE batch<float, A> load_aligned(float const* mem, convert<float>, requires_arch<sse2>) noexcept
1053
+ {
1054
+ return _mm_load_ps(mem);
1055
+ }
1056
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
1057
+ XSIMD_INLINE batch<T, A> load_aligned(T const* mem, convert<T>, requires_arch<sse2>) noexcept
1058
+ {
1059
+ return _mm_load_si128((__m128i const*)mem);
1060
+ }
1061
+ template <class A>
1062
+ XSIMD_INLINE batch<double, A> load_aligned(double const* mem, convert<double>, requires_arch<sse2>) noexcept
1063
+ {
1064
+ return _mm_load_pd(mem);
1065
+ }
1066
+
1067
+ // load_unaligned
1068
+ template <class A>
1069
+ XSIMD_INLINE batch<float, A> load_unaligned(float const* mem, convert<float>, requires_arch<sse2>) noexcept
1070
+ {
1071
+ return _mm_loadu_ps(mem);
1072
+ }
1073
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
1074
+ XSIMD_INLINE batch<T, A> load_unaligned(T const* mem, convert<T>, requires_arch<sse2>) noexcept
1075
+ {
1076
+ return _mm_loadu_si128((__m128i const*)mem);
1077
+ }
1078
+ template <class A>
1079
+ XSIMD_INLINE batch<double, A> load_unaligned(double const* mem, convert<double>, requires_arch<sse2>) noexcept
1080
+ {
1081
+ return _mm_loadu_pd(mem);
1082
+ }
1083
+ // load batch_bool
1084
+
1085
+ template <class A>
1086
+ XSIMD_INLINE batch_bool<char, A> load_unaligned(bool const* mem, batch_bool<char, A>, requires_arch<sse2>) noexcept
1087
+ {
1088
+ return _mm_sub_epi8(_mm_set1_epi8(0), _mm_loadu_si128((__m128i const*)mem));
1089
+ }
1090
+
1091
+ template <class A>
1092
+ XSIMD_INLINE batch_bool<unsigned char, A> load_unaligned(bool const* mem, batch_bool<unsigned char, A>, requires_arch<sse2> r) noexcept
1093
+ {
1094
+ return { load_unaligned(mem, batch_bool<char, A> {}, r).data };
1095
+ }
1096
+
1097
+ template <class A>
1098
+ XSIMD_INLINE batch_bool<signed char, A> load_unaligned(bool const* mem, batch_bool<signed char, A>, requires_arch<sse2> r) noexcept
1099
+ {
1100
+ return { load_unaligned(mem, batch_bool<char, A> {}, r).data };
1101
+ }
1102
+
1103
+ // load_masked
1104
+ template <class A, class T, bool... Values, class Mode, class = std::enable_if_t<std::is_integral<T>::value>>
1105
+ XSIMD_INLINE batch<T, A> load_masked(T const* mem, batch_bool_constant<T, A, Values...> mask, Mode, requires_arch<sse2>) noexcept
1106
+ {
1107
+ XSIMD_IF_CONSTEXPR(mask.mask() == 0x1)
1108
+ {
1109
+ XSIMD_IF_CONSTEXPR(sizeof(T) == 2)
1110
+ {
1111
+ return mm_loadu_si16(mem);
1112
+ }
1113
+ XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
1114
+ {
1115
+ return mm_loadu_si32(mem);
1116
+ }
1117
+ XSIMD_IF_CONSTEXPR(sizeof(T) == 8)
1118
+ {
1119
+ return mm_loadu_si64(mem);
1120
+ }
1121
+ }
1122
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 2 && mask.mask() == 0x3)
1123
+ {
1124
+ return mm_loadu_si32(mem);
1125
+ }
1126
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 4 && mask.mask() == 0x3)
1127
+ {
1128
+ return mm_loadu_si64(mem);
1129
+ }
1130
+ else
1131
+ {
1132
+ return load_masked<A>(mem, mask, convert<T> {}, Mode {}, common {});
1133
+ }
1134
+ }
1135
+ template <class A, bool... Values, class Mode>
1136
+ XSIMD_INLINE batch<float, A> load_masked(float const* mem, batch_bool_constant<float, A, Values...> mask, Mode, requires_arch<sse2>) noexcept
1137
+ {
1138
+ XSIMD_IF_CONSTEXPR(mask.mask() == 0x1)
1139
+ {
1140
+ return _mm_load_ss(mem);
1141
+ }
1142
+ else XSIMD_IF_CONSTEXPR(mask.countr_one() == 2)
1143
+ {
1144
+ return _mm_loadl_pi(_mm_setzero_ps(), reinterpret_cast<__m64 const*>(mem));
1145
+ }
1146
+ else XSIMD_IF_CONSTEXPR(mask.countl_one() == 2)
1147
+ {
1148
+ return _mm_loadh_pi(_mm_setzero_ps(), reinterpret_cast<__m64 const*>(mem + 2));
1149
+ }
1150
+ else
1151
+ {
1152
+ return load_masked<A>(mem, mask, convert<float> {}, Mode {}, common {});
1153
+ }
1154
+ }
1155
+ template <class A, bool... Values, class Mode>
1156
+ XSIMD_INLINE batch<double, A> load_masked(double const* mem, batch_bool_constant<double, A, Values...> mask, Mode, requires_arch<sse2>) noexcept
1157
+ {
1158
+ XSIMD_IF_CONSTEXPR(mask.countr_one() == 1)
1159
+ {
1160
+ return _mm_load_sd(mem);
1161
+ }
1162
+ else XSIMD_IF_CONSTEXPR(mask.countl_one() == 1)
1163
+ {
1164
+ return _mm_loadh_pd(_mm_setzero_pd(), mem + 1);
1165
+ }
1166
+ else
1167
+ {
1168
+ return load_masked<A>(mem, mask, convert<double> {}, Mode {}, common {});
1169
+ }
1170
+ }
1171
+
1172
+ // store_masked
1173
+ template <class A, bool... Values, class Mode>
1174
+ XSIMD_INLINE void store_masked(float* mem, batch<float, A> const& src, batch_bool_constant<float, A, Values...> mask, Mode, requires_arch<sse2>) noexcept
1175
+ {
1176
+ XSIMD_IF_CONSTEXPR(mask.mask() == 0x1)
1177
+ {
1178
+ _mm_store_ss(mem, src);
1179
+ }
1180
+ else XSIMD_IF_CONSTEXPR(mask.countr_one() == 2)
1181
+ {
1182
+ _mm_storel_pi(reinterpret_cast<__m64*>(mem), src);
1183
+ }
1184
+ else XSIMD_IF_CONSTEXPR(mask.countl_one() == 2)
1185
+ {
1186
+ _mm_storeh_pi(reinterpret_cast<__m64*>(mem + 2), src);
1187
+ }
1188
+ else
1189
+ {
1190
+ store_masked<A>(mem, src, mask, Mode {}, common {});
1191
+ }
1192
+ }
1193
+
1194
+ template <class A, bool... Values, class Mode>
1195
+ XSIMD_INLINE void store_masked(double* mem, batch<double, A> const& src, batch_bool_constant<double, A, Values...> mask, Mode, requires_arch<sse2>) noexcept
1196
+ {
1197
+ XSIMD_IF_CONSTEXPR(mask.countr_one() == 1)
1198
+ {
1199
+ _mm_store_sd(mem, src);
1200
+ }
1201
+ else XSIMD_IF_CONSTEXPR(mask.countl_one() == 1)
1202
+ {
1203
+ _mm_storeh_pd(mem + 1, src);
1204
+ }
1205
+ else
1206
+ {
1207
+ store_masked<A>(mem, src, mask, Mode {}, common {});
1208
+ }
1209
+ }
1210
+
1211
+ // load_complex
1212
+ namespace detail
1213
+ {
1214
+ // Redefine these methods in the SSE-based archs if required
1215
+ template <class A>
1216
+ XSIMD_INLINE batch<std::complex<float>, A> load_complex(batch<float, A> const& hi, batch<float, A> const& lo, requires_arch<sse2>) noexcept
1217
+ {
1218
+ return { _mm_shuffle_ps(hi, lo, _MM_SHUFFLE(2, 0, 2, 0)), _mm_shuffle_ps(hi, lo, _MM_SHUFFLE(3, 1, 3, 1)) };
1219
+ }
1220
+ template <class A>
1221
+ XSIMD_INLINE batch<std::complex<double>, A> load_complex(batch<double, A> const& hi, batch<double, A> const& lo, requires_arch<sse2>) noexcept
1222
+ {
1223
+ return { _mm_shuffle_pd(hi, lo, _MM_SHUFFLE2(0, 0)), _mm_shuffle_pd(hi, lo, _MM_SHUFFLE2(1, 1)) };
1224
+ }
1225
+ }
1226
+
1227
+ // le
1228
+ template <class A>
1229
+ XSIMD_INLINE batch_bool<float, A> le(batch<float, A> const& self, batch<float, A> const& other, requires_arch<sse2>) noexcept
1230
+ {
1231
+ return _mm_cmple_ps(self, other);
1232
+ }
1233
+ template <class A>
1234
+ XSIMD_INLINE batch_bool<double, A> le(batch<double, A> const& self, batch<double, A> const& other, requires_arch<sse2>) noexcept
1235
+ {
1236
+ return _mm_cmple_pd(self, other);
1237
+ }
1238
+
1239
+ // lt
1240
+ template <class A>
1241
+ XSIMD_INLINE batch_bool<float, A> lt(batch<float, A> const& self, batch<float, A> const& other, requires_arch<sse2>) noexcept
1242
+ {
1243
+ return _mm_cmplt_ps(self, other);
1244
+ }
1245
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
1246
+ XSIMD_INLINE batch_bool<T, A> lt(batch<T, A> const& self, batch<T, A> const& other, requires_arch<sse2>) noexcept
1247
+ {
1248
+ if (std::is_signed<T>::value)
1249
+ {
1250
+ XSIMD_IF_CONSTEXPR(sizeof(T) == 1)
1251
+ {
1252
+ return _mm_cmplt_epi8(self, other);
1253
+ }
1254
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 2)
1255
+ {
1256
+ return _mm_cmplt_epi16(self, other);
1257
+ }
1258
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
1259
+ {
1260
+ return _mm_cmplt_epi32(self, other);
1261
+ }
1262
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 8)
1263
+ {
1264
+ __m128i tmp1 = _mm_sub_epi64(self, other);
1265
+ __m128i tmp2 = _mm_xor_si128(self, other);
1266
+ __m128i tmp3 = _mm_andnot_si128(other, self);
1267
+ __m128i tmp4 = _mm_andnot_si128(tmp2, tmp1);
1268
+ __m128i tmp5 = _mm_or_si128(tmp3, tmp4);
1269
+ __m128i tmp6 = _mm_srai_epi32(tmp5, 31);
1270
+ return _mm_shuffle_epi32(tmp6, 0xF5);
1271
+ }
1272
+ else
1273
+ {
1274
+ assert(false && "unsupported arch/op combination");
1275
+ return {};
1276
+ }
1277
+ }
1278
+ else
1279
+ {
1280
+ XSIMD_IF_CONSTEXPR(sizeof(T) == 1)
1281
+ {
1282
+ return _mm_cmplt_epi8(_mm_xor_si128(self, _mm_set1_epi8(std::numeric_limits<int8_t>::lowest())), _mm_xor_si128(other, _mm_set1_epi8(std::numeric_limits<int8_t>::lowest())));
1283
+ }
1284
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 2)
1285
+ {
1286
+ return _mm_cmplt_epi16(_mm_xor_si128(self, _mm_set1_epi16(std::numeric_limits<int16_t>::lowest())), _mm_xor_si128(other, _mm_set1_epi16(std::numeric_limits<int16_t>::lowest())));
1287
+ }
1288
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
1289
+ {
1290
+ return _mm_cmplt_epi32(_mm_xor_si128(self, _mm_set1_epi32(std::numeric_limits<int32_t>::lowest())), _mm_xor_si128(other, _mm_set1_epi32(std::numeric_limits<int32_t>::lowest())));
1291
+ }
1292
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 8)
1293
+ {
1294
+ auto xself = _mm_xor_si128(self, _mm_set1_epi64x(std::numeric_limits<int64_t>::lowest()));
1295
+ auto xother = _mm_xor_si128(other, _mm_set1_epi64x(std::numeric_limits<int64_t>::lowest()));
1296
+ __m128i tmp1 = _mm_sub_epi64(xself, xother);
1297
+ __m128i tmp2 = _mm_xor_si128(xself, xother);
1298
+ __m128i tmp3 = _mm_andnot_si128(xother, xself);
1299
+ __m128i tmp4 = _mm_andnot_si128(tmp2, tmp1);
1300
+ __m128i tmp5 = _mm_or_si128(tmp3, tmp4);
1301
+ __m128i tmp6 = _mm_srai_epi32(tmp5, 31);
1302
+ return _mm_shuffle_epi32(tmp6, 0xF5);
1303
+ }
1304
+ else
1305
+ {
1306
+ assert(false && "unsupported arch/op combination");
1307
+ return {};
1308
+ }
1309
+ }
1310
+ }
1311
+
1312
+ template <class A>
1313
+ XSIMD_INLINE batch_bool<double, A> lt(batch<double, A> const& self, batch<double, A> const& other, requires_arch<sse2>) noexcept
1314
+ {
1315
+ return _mm_cmplt_pd(self, other);
1316
+ }
1317
+
1318
+ /* compression table to turn 0b10 into 0b1,
1319
+ * 0b100010 into 0b101 etc
1320
+ */
1321
+ namespace detail
1322
+ {
1323
+ XSIMD_INLINE int mask_lut(uint64_t mask)
1324
+ {
1325
+ // clang-format off
1326
+ static const int mask_lut[256] = {
1327
+ 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x0, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0,
1328
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
1329
+ 0x4, 0x0, 0x5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6, 0x0, 0x7, 0x0, 0x0, 0x0, 0x0, 0x0,
1330
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
1331
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
1332
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
1333
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
1334
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
1335
+ 0x8, 0x0, 0x9, 0x0, 0x0, 0x0, 0x0, 0x0, 0xA, 0x0, 0xB, 0x0, 0x0, 0x0, 0x0, 0x0,
1336
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
1337
+ 0xC, 0x0, 0xD, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE, 0x0, 0xF, 0x0, 0x0, 0x0, 0x0, 0x0,
1338
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
1339
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
1340
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
1341
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
1342
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
1343
+ };
1344
+ // clang-format on
1345
+ return mask_lut[mask & 0xAA];
1346
+ }
1347
+ }
1348
+
1349
+ // mask
1350
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
1351
+ XSIMD_INLINE uint64_t mask(batch_bool<T, A> const& self, requires_arch<sse2>) noexcept
1352
+ {
1353
+ XSIMD_IF_CONSTEXPR(sizeof(T) == 1)
1354
+ {
1355
+ return _mm_movemask_epi8(self);
1356
+ }
1357
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 2)
1358
+ {
1359
+ uint64_t mask8 = _mm_movemask_epi8(self);
1360
+ return detail::mask_lut(mask8) | (detail::mask_lut(mask8 >> 8) << 4);
1361
+ }
1362
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
1363
+ {
1364
+ return _mm_movemask_ps(_mm_castsi128_ps(self));
1365
+ }
1366
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 8)
1367
+ {
1368
+ return _mm_movemask_pd(_mm_castsi128_pd(self));
1369
+ }
1370
+ else
1371
+ {
1372
+ assert(false && "unsupported arch/op combination");
1373
+ return {};
1374
+ }
1375
+ }
1376
+ template <class A>
1377
+ XSIMD_INLINE uint64_t mask(batch_bool<float, A> const& self, requires_arch<sse2>) noexcept
1378
+ {
1379
+ return _mm_movemask_ps(self);
1380
+ }
1381
+
1382
+ template <class A>
1383
+ XSIMD_INLINE uint64_t mask(batch_bool<double, A> const& self, requires_arch<sse2>) noexcept
1384
+ {
1385
+ return _mm_movemask_pd(self);
1386
+ }
1387
+
1388
+ // max
1389
+ template <class A>
1390
+ XSIMD_INLINE batch<float, A> max(batch<float, A> const& self, batch<float, A> const& other, requires_arch<sse2>) noexcept
1391
+ {
1392
+ return _mm_max_ps(other, self);
1393
+ }
1394
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
1395
+ XSIMD_INLINE batch<T, A> max(batch<T, A> const& self, batch<T, A> const& other, requires_arch<sse2>) noexcept
1396
+ {
1397
+ return select(self > other, self, other);
1398
+ }
1399
+ template <class A>
1400
+ XSIMD_INLINE batch<double, A> max(batch<double, A> const& self, batch<double, A> const& other, requires_arch<sse2>) noexcept
1401
+ {
1402
+ return _mm_max_pd(other, self);
1403
+ }
1404
+
1405
+ // min
1406
+ template <class A>
1407
+ XSIMD_INLINE batch<float, A> min(batch<float, A> const& self, batch<float, A> const& other, requires_arch<sse2>) noexcept
1408
+ {
1409
+ return _mm_min_ps(other, self);
1410
+ }
1411
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
1412
+ XSIMD_INLINE batch<T, A> min(batch<T, A> const& self, batch<T, A> const& other, requires_arch<sse2>) noexcept
1413
+ {
1414
+ return select(self <= other, self, other);
1415
+ }
1416
+ template <class A>
1417
+ XSIMD_INLINE batch<double, A> min(batch<double, A> const& self, batch<double, A> const& other, requires_arch<sse2>) noexcept
1418
+ {
1419
+ return _mm_min_pd(other, self);
1420
+ }
1421
+
1422
+ // mul
1423
+ template <class A>
1424
+ XSIMD_INLINE batch<float, A> mul(batch<float, A> const& self, batch<float, A> const& other, requires_arch<sse2>) noexcept
1425
+ {
1426
+ return _mm_mul_ps(self, other);
1427
+ }
1428
+ template <class A>
1429
+ XSIMD_INLINE batch<double, A> mul(batch<double, A> const& self, batch<double, A> const& other, requires_arch<sse2>) noexcept
1430
+ {
1431
+ return _mm_mul_pd(self, other);
1432
+ }
1433
+
1434
+ // mul
1435
+ template <class A>
1436
+ XSIMD_INLINE batch<int16_t, A> mul(batch<int16_t, A> const& self, batch<int16_t, A> const& other, requires_arch<sse2>) noexcept
1437
+ {
1438
+ return _mm_mullo_epi16(self, other);
1439
+ }
1440
+
1441
+ // nearbyint_as_int
1442
+ template <class A>
1443
+ XSIMD_INLINE batch<int32_t, A> nearbyint_as_int(batch<float, A> const& self,
1444
+ requires_arch<sse2>) noexcept
1445
+ {
1446
+ return _mm_cvtps_epi32(self);
1447
+ }
1448
+
1449
+ // neg
1450
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
1451
+ XSIMD_INLINE batch<T, A> neg(batch<T, A> const& self, requires_arch<sse2>) noexcept
1452
+ {
1453
+ return 0 - self;
1454
+ }
1455
+ template <class A>
1456
+ XSIMD_INLINE batch<float, A> neg(batch<float, A> const& self, requires_arch<sse2>) noexcept
1457
+ {
1458
+ return _mm_xor_ps(self, _mm_castsi128_ps(_mm_set1_epi32(0x80000000)));
1459
+ }
1460
+
1461
+ template <class A>
1462
+ XSIMD_INLINE batch<double, A> neg(batch<double, A> const& self, requires_arch<sse2>) noexcept
1463
+ {
1464
+ return _mm_xor_pd(
1465
+ self, _mm_castsi128_pd(_mm_setr_epi32(0, 0x80000000, 0, 0x80000000)));
1466
+ }
1467
+
1468
+ // neq
1469
+ template <class A>
1470
+ XSIMD_INLINE batch_bool<float, A> neq(batch<float, A> const& self, batch<float, A> const& other, requires_arch<sse2>) noexcept
1471
+ {
1472
+ return _mm_cmpneq_ps(self, other);
1473
+ }
1474
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
1475
+ XSIMD_INLINE batch_bool<T, A> neq(batch<T, A> const& self, batch<T, A> const& other, requires_arch<sse2>) noexcept
1476
+ {
1477
+ return ~(self == other);
1478
+ }
1479
+ template <class A>
1480
+ XSIMD_INLINE batch_bool<float, A> neq(batch_bool<float, A> const& self, batch_bool<float, A> const& other, requires_arch<sse2>) noexcept
1481
+ {
1482
+ return _mm_xor_ps(self, other);
1483
+ }
1484
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
1485
+ XSIMD_INLINE batch_bool<T, A> neq(batch_bool<T, A> const& self, batch_bool<T, A> const& other, requires_arch<sse2>) noexcept
1486
+ {
1487
+ return _mm_castps_si128(_mm_xor_ps(_mm_castsi128_ps(self.data), _mm_castsi128_ps(other.data)));
1488
+ }
1489
+
1490
+ template <class A>
1491
+ XSIMD_INLINE batch_bool<double, A> neq(batch<double, A> const& self, batch<double, A> const& other, requires_arch<sse2>) noexcept
1492
+ {
1493
+ return _mm_cmpneq_pd(self, other);
1494
+ }
1495
+ template <class A>
1496
+ XSIMD_INLINE batch_bool<double, A> neq(batch_bool<double, A> const& self, batch_bool<double, A> const& other, requires_arch<sse2>) noexcept
1497
+ {
1498
+ return _mm_xor_pd(self, other);
1499
+ }
1500
+
1501
+ // reciprocal
1502
+ template <class A>
1503
+ XSIMD_INLINE batch<float, A> reciprocal(batch<float, A> const& self,
1504
+ kernel::requires_arch<sse2>)
1505
+ {
1506
+ return _mm_rcp_ps(self);
1507
+ }
1508
+
1509
+ // reduce_add
1510
+ template <class A>
1511
+ XSIMD_INLINE float reduce_add(batch<float, A> const& self, requires_arch<sse2>) noexcept
1512
+ {
1513
+ __m128 tmp0 = _mm_add_ps(self, _mm_movehl_ps(self, self));
1514
+ __m128 tmp1 = _mm_add_ss(tmp0, _mm_shuffle_ps(tmp0, tmp0, 1));
1515
+ return _mm_cvtss_f32(tmp1);
1516
+ }
1517
+
1518
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
1519
+ XSIMD_INLINE T reduce_add(batch<T, A> const& self, requires_arch<sse2>) noexcept
1520
+ {
1521
+ XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
1522
+ {
1523
+ __m128i tmp1 = _mm_shuffle_epi32(self, 0x0E);
1524
+ __m128i tmp2 = _mm_add_epi32(self, tmp1);
1525
+ __m128i tmp3 = _mm_shuffle_epi32(tmp2, 0x01);
1526
+ __m128i tmp4 = _mm_add_epi32(tmp2, tmp3);
1527
+ return _mm_cvtsi128_si32(tmp4);
1528
+ }
1529
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 8)
1530
+ {
1531
+ __m128i tmp1 = _mm_shuffle_epi32(self, 0x0E);
1532
+ __m128i tmp2 = _mm_add_epi64(self, tmp1);
1533
+ #if defined(__x86_64__)
1534
+ return _mm_cvtsi128_si64(tmp2);
1535
+ #else
1536
+ __m128i m;
1537
+ _mm_storel_epi64(&m, tmp2);
1538
+ int64_t i;
1539
+ std::memcpy(&i, &m, sizeof(i));
1540
+ return i;
1541
+ #endif
1542
+ }
1543
+ else
1544
+ {
1545
+ return reduce_add(self, common {});
1546
+ }
1547
+ }
1548
+
1549
+ template <class A>
1550
+ XSIMD_INLINE double reduce_add(batch<double, A> const& self, requires_arch<sse2>) noexcept
1551
+ {
1552
+ return _mm_cvtsd_f64(_mm_add_sd(self, _mm_unpackhi_pd(self, self)));
1553
+ }
1554
+
1555
+ // reduce_max
1556
+ template <class A, class T, class = std::enable_if_t<(sizeof(T) <= 2)>>
1557
+ XSIMD_INLINE T reduce_max(batch<T, A> const& self, requires_arch<sse2>) noexcept
1558
+ {
1559
+ constexpr auto mask0 = detail::shuffle(2, 3, 0, 0);
1560
+ batch<T, A> step0 = _mm_shuffle_epi32(self, mask0);
1561
+ batch<T, A> acc0 = max(self, step0);
1562
+
1563
+ constexpr auto mask1 = detail::shuffle(1, 0, 0, 0);
1564
+ batch<T, A> step1 = _mm_shuffle_epi32(acc0, mask1);
1565
+ batch<T, A> acc1 = max(acc0, step1);
1566
+
1567
+ constexpr auto mask2 = detail::shuffle(1, 0, 0, 0);
1568
+ batch<T, A> step2 = _mm_shufflelo_epi16(acc1, mask2);
1569
+ batch<T, A> acc2 = max(acc1, step2);
1570
+ if (sizeof(T) == 2)
1571
+ return first(acc2, A {});
1572
+ batch<T, A> step3 = bitwise_cast<T>(bitwise_cast<uint16_t>(acc2) >> 8);
1573
+ batch<T, A> acc3 = max(acc2, step3);
1574
+ return first(acc3, A {});
1575
+ }
1576
+
1577
+ // reduce_min
1578
+ template <class A, class T, class = std::enable_if_t<(sizeof(T) <= 2)>>
1579
+ XSIMD_INLINE T reduce_min(batch<T, A> const& self, requires_arch<sse2>) noexcept
1580
+ {
1581
+ constexpr auto mask0 = detail::shuffle(2, 3, 0, 0);
1582
+ batch<T, A> step0 = _mm_shuffle_epi32(self, mask0);
1583
+ batch<T, A> acc0 = min(self, step0);
1584
+
1585
+ constexpr auto mask1 = detail::shuffle(1, 0, 0, 0);
1586
+ batch<T, A> step1 = _mm_shuffle_epi32(acc0, mask1);
1587
+ batch<T, A> acc1 = min(acc0, step1);
1588
+
1589
+ constexpr auto mask2 = detail::shuffle(1, 0, 0, 0);
1590
+ batch<T, A> step2 = _mm_shufflelo_epi16(acc1, mask2);
1591
+ batch<T, A> acc2 = min(acc1, step2);
1592
+ if (sizeof(T) == 2)
1593
+ return first(acc2, A {});
1594
+ batch<T, A> step3 = bitwise_cast<T>(bitwise_cast<uint16_t>(acc2) >> 8);
1595
+ batch<T, A> acc3 = min(acc2, step3);
1596
+ return first(acc3, A {});
1597
+ }
1598
+
1599
+ // reduce_mul
1600
+ template <class A>
1601
+ XSIMD_INLINE float reduce_mul(batch<float, A> const& self, requires_arch<sse2>) noexcept
1602
+ {
1603
+ __m128 tmp0 = _mm_mul_ps(self, _mm_movehl_ps(self, self));
1604
+ __m128 tmp1 = _mm_mul_ss(tmp0, _mm_shuffle_ps(tmp0, tmp0, 1));
1605
+ return _mm_cvtss_f32(tmp1);
1606
+ }
1607
+
1608
+ template <class A>
1609
+ XSIMD_INLINE double reduce_mul(batch<double, A> const& self, requires_arch<sse2>) noexcept
1610
+ {
1611
+ return _mm_cvtsd_f64(_mm_mul_sd(self, _mm_unpackhi_pd(self, self)));
1612
+ }
1613
+
1614
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
1615
+ XSIMD_INLINE T reduce_mul(batch<T, A> const& self, requires_arch<sse2>) noexcept
1616
+ {
1617
+ XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
1618
+ {
1619
+ batch<T, A> tmp1 = _mm_shuffle_epi32(self, _MM_SHUFFLE(0, 1, 2, 3));
1620
+ tmp1 = tmp1 * self;
1621
+ batch<T, A> tmp2 = _mm_unpackhi_epi32(tmp1, tmp1);
1622
+ tmp2 = tmp2 * tmp1;
1623
+ return _mm_cvtsi128_si32(tmp2);
1624
+ }
1625
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 8)
1626
+ {
1627
+ batch<T, A> tmp1 = _mm_unpackhi_epi64(self, self);
1628
+ auto tmp2 = tmp1 * self;
1629
+ #if defined(__x86_64__)
1630
+ return _mm_cvtsi128_si64(tmp2);
1631
+ #else
1632
+ __m128i m;
1633
+ _mm_storel_epi64(&m, tmp2);
1634
+ int64_t i;
1635
+ std::memcpy(&i, &m, sizeof(i));
1636
+ return i;
1637
+ #endif
1638
+ }
1639
+ else
1640
+ {
1641
+ return reduce_mul(self, common {});
1642
+ }
1643
+ }
1644
+
1645
+ // rsqrt
1646
+ template <class A>
1647
+ XSIMD_INLINE batch<float, A> rsqrt(batch<float, A> const& val, requires_arch<sse2>) noexcept
1648
+ {
1649
+ return _mm_rsqrt_ps(val);
1650
+ }
1651
+ template <class A>
1652
+ XSIMD_INLINE batch<double, A> rsqrt(batch<double, A> const& val, requires_arch<sse2>) noexcept
1653
+ {
1654
+ return _mm_cvtps_pd(_mm_rsqrt_ps(_mm_cvtpd_ps(val)));
1655
+ }
1656
+
1657
+ // select
1658
+ template <class A>
1659
+ 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<sse2>) noexcept
1660
+ {
1661
+ return _mm_or_ps(_mm_and_ps(cond, true_br), _mm_andnot_ps(cond, false_br));
1662
+ }
1663
+
1664
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
1665
+ 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<sse2>) noexcept
1666
+ {
1667
+ return _mm_or_si128(_mm_and_si128(cond, true_br), _mm_andnot_si128(cond, false_br));
1668
+ }
1669
+ template <class A, class T, bool... Values, class = std::enable_if_t<std::is_integral<T>::value>>
1670
+ 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<sse2>) noexcept
1671
+ {
1672
+ return select(batch_bool<T, A> { Values... }, true_br, false_br, sse2 {});
1673
+ }
1674
+ template <class A>
1675
+ 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<sse2>) noexcept
1676
+ {
1677
+ return _mm_or_pd(_mm_and_pd(cond, true_br), _mm_andnot_pd(cond, false_br));
1678
+ }
1679
+
1680
+ // shuffle
1681
+ template <class A, class ITy, ITy I0, ITy I1, ITy I2, ITy I3>
1682
+ XSIMD_INLINE batch<float, A> shuffle(batch<float, A> const& x, batch<float, A> const& y, batch_constant<ITy, A, I0, I1, I2, I3> mask, requires_arch<sse2>) noexcept
1683
+ {
1684
+ constexpr uint32_t smask = detail::mod_shuffle(I0, I1, I2, I3);
1685
+ // shuffle within lane
1686
+ if (I0 < 4 && I1 < 4 && I2 >= 4 && I3 >= 4)
1687
+ return _mm_shuffle_ps(x, y, smask);
1688
+
1689
+ // shuffle within opposite lane
1690
+ if (I0 >= 4 && I1 >= 4 && I2 < 4 && I3 < 4)
1691
+ return _mm_shuffle_ps(y, x, smask);
1692
+ return shuffle(x, y, mask, common {});
1693
+ }
1694
+
1695
+ template <class A, class ITy, ITy I0, ITy I1>
1696
+ XSIMD_INLINE batch<double, A> shuffle(batch<double, A> const& x, batch<double, A> const& y, batch_constant<ITy, A, I0, I1> mask, requires_arch<sse2>) noexcept
1697
+ {
1698
+ constexpr uint32_t smask = detail::mod_shuffle(I0, I1);
1699
+ // shuffle within lane
1700
+ if (I0 < 2 && I1 >= 2)
1701
+ return _mm_shuffle_pd(x, y, smask);
1702
+
1703
+ // shuffle within opposite lane
1704
+ if (I0 >= 2 && I1 < 2)
1705
+ return _mm_shuffle_pd(y, x, smask);
1706
+ return shuffle(x, y, mask, common {});
1707
+ }
1708
+
1709
+ // sqrt
1710
+ template <class A>
1711
+ XSIMD_INLINE batch<float, A> sqrt(batch<float, A> const& val, requires_arch<sse2>) noexcept
1712
+ {
1713
+ return _mm_sqrt_ps(val);
1714
+ }
1715
+ template <class A>
1716
+ XSIMD_INLINE batch<double, A> sqrt(batch<double, A> const& val, requires_arch<sse2>) noexcept
1717
+ {
1718
+ return _mm_sqrt_pd(val);
1719
+ }
1720
+
1721
+ // slide_left
1722
+ template <size_t N, class A, class T>
1723
+ XSIMD_INLINE batch<T, A> slide_left(batch<T, A> const& x, requires_arch<sse2>) noexcept
1724
+ {
1725
+ return _mm_slli_si128(x, N);
1726
+ }
1727
+
1728
+ // slide_right
1729
+ template <size_t N, class A, class T>
1730
+ XSIMD_INLINE batch<T, A> slide_right(batch<T, A> const& x, requires_arch<sse2>) noexcept
1731
+ {
1732
+ return _mm_srli_si128(x, N);
1733
+ }
1734
+
1735
+ // sadd
1736
+
1737
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
1738
+ XSIMD_INLINE batch<T, A> sadd(batch<T, A> const& self, batch<T, A> const& other, requires_arch<sse2>) noexcept
1739
+ {
1740
+ if (std::is_signed<T>::value)
1741
+ {
1742
+ XSIMD_IF_CONSTEXPR(sizeof(T) == 1)
1743
+ {
1744
+ return _mm_adds_epi8(self, other);
1745
+ }
1746
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 2)
1747
+ {
1748
+ return _mm_adds_epi16(self, other);
1749
+ }
1750
+ else
1751
+ {
1752
+ return sadd(self, other, common {});
1753
+ }
1754
+ }
1755
+ else
1756
+ {
1757
+ XSIMD_IF_CONSTEXPR(sizeof(T) == 1)
1758
+ {
1759
+ return _mm_adds_epu8(self, other);
1760
+ }
1761
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 2)
1762
+ {
1763
+ return _mm_adds_epu16(self, other);
1764
+ }
1765
+ else
1766
+ {
1767
+ return sadd(self, other, common {});
1768
+ }
1769
+ }
1770
+ }
1771
+
1772
+ // set
1773
+ template <class A, class... Values>
1774
+ XSIMD_INLINE batch<float, A> set(batch<float, A> const&, requires_arch<sse2>, Values... values) noexcept
1775
+ {
1776
+ static_assert(sizeof...(Values) == batch<float, A>::size, "consistent init");
1777
+ return _mm_setr_ps(values...);
1778
+ }
1779
+
1780
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
1781
+ XSIMD_INLINE batch<T, A> set(batch<T, A> const&, requires_arch<sse2>, T v0, T v1) noexcept
1782
+ {
1783
+ return _mm_set_epi64x(v1, v0);
1784
+ }
1785
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
1786
+ XSIMD_INLINE batch<T, A> set(batch<T, A> const&, requires_arch<sse2>, T v0, T v1, T v2, T v3) noexcept
1787
+ {
1788
+ return _mm_setr_epi32(v0, v1, v2, v3);
1789
+ }
1790
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
1791
+ XSIMD_INLINE batch<T, A> set(batch<T, A> const&, requires_arch<sse2>, T v0, T v1, T v2, T v3, T v4, T v5, T v6, T v7) noexcept
1792
+ {
1793
+ return _mm_setr_epi16(v0, v1, v2, v3, v4, v5, v6, v7);
1794
+ }
1795
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
1796
+ XSIMD_INLINE batch<T, A> set(batch<T, A> const&, requires_arch<sse2>, 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
1797
+ {
1798
+ return _mm_setr_epi8(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15);
1799
+ }
1800
+
1801
+ template <class A, class... Values>
1802
+ XSIMD_INLINE batch<double, A> set(batch<double, A> const&, requires_arch<sse2>, Values... values) noexcept
1803
+ {
1804
+ static_assert(sizeof...(Values) == batch<double, A>::size, "consistent init");
1805
+ return _mm_setr_pd(values...);
1806
+ }
1807
+
1808
+ template <class A, class T, class... Values, class = std::enable_if_t<std::is_integral<T>::value>>
1809
+ XSIMD_INLINE batch_bool<T, A> set(batch_bool<T, A> const&, requires_arch<sse2>, Values... values) noexcept
1810
+ {
1811
+ return set(batch<T, A>(), A {}, static_cast<T>(values ? -1LL : 0LL)...).data;
1812
+ }
1813
+
1814
+ template <class A, class... Values>
1815
+ XSIMD_INLINE batch_bool<float, A> set(batch_bool<float, A> const&, requires_arch<sse2>, Values... values) noexcept
1816
+ {
1817
+ static_assert(sizeof...(Values) == batch_bool<float, A>::size, "consistent init");
1818
+ return _mm_castsi128_ps(set(batch<int32_t, A>(), A {}, static_cast<int32_t>(values ? -1LL : 0LL)...).data);
1819
+ }
1820
+
1821
+ template <class A, class... Values>
1822
+ XSIMD_INLINE batch_bool<double, A> set(batch_bool<double, A> const&, requires_arch<sse2>, Values... values) noexcept
1823
+ {
1824
+ static_assert(sizeof...(Values) == batch_bool<double, A>::size, "consistent init");
1825
+ return _mm_castsi128_pd(set(batch<int64_t, A>(), A {}, static_cast<int64_t>(values ? -1LL : 0LL)...).data);
1826
+ }
1827
+
1828
+ // ssub
1829
+
1830
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
1831
+ XSIMD_INLINE batch<T, A> ssub(batch<T, A> const& self, batch<T, A> const& other, requires_arch<sse2>) noexcept
1832
+ {
1833
+ if (std::is_signed<T>::value)
1834
+ {
1835
+ XSIMD_IF_CONSTEXPR(sizeof(T) == 1)
1836
+ {
1837
+ return _mm_subs_epi8(self, other);
1838
+ }
1839
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 2)
1840
+ {
1841
+ return _mm_subs_epi16(self, other);
1842
+ }
1843
+ else
1844
+ {
1845
+ return ssub(self, other, common {});
1846
+ }
1847
+ }
1848
+ else
1849
+ {
1850
+ XSIMD_IF_CONSTEXPR(sizeof(T) == 1)
1851
+ {
1852
+ return _mm_subs_epu8(self, other);
1853
+ }
1854
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 2)
1855
+ {
1856
+ return _mm_subs_epu16(self, other);
1857
+ }
1858
+ else
1859
+ {
1860
+ return ssub(self, other, common {});
1861
+ }
1862
+ }
1863
+ }
1864
+
1865
+ // store<batch_bool>
1866
+ namespace detail
1867
+ {
1868
+ template <class T>
1869
+ XSIMD_INLINE void store_bool_sse2(__m128i b, bool* mem, T) noexcept
1870
+ {
1871
+ // GCC <12 have missing or buggy unaligned store intrinsics; use memcpy to work around this.
1872
+ // GCC/Clang/MSVC will turn it into the correct store.
1873
+ XSIMD_IF_CONSTEXPR(sizeof(T) == 1)
1874
+ {
1875
+ // negate mask to convert to 0 or 1
1876
+ auto val = _mm_sub_epi8(_mm_set1_epi8(0), b);
1877
+ memcpy(mem, &val, sizeof(val));
1878
+ }
1879
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 2)
1880
+ {
1881
+ auto val = _mm_sub_epi8(_mm_set1_epi8(0), _mm_packs_epi16(b, b));
1882
+ #if defined(__x86_64__)
1883
+ auto val_lo = _mm_cvtsi128_si64(val);
1884
+ memcpy(mem, &val_lo, sizeof(val_lo));
1885
+ #else
1886
+ memcpy(mem, &val, sizeof(uint64_t));
1887
+ #endif
1888
+ }
1889
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
1890
+ {
1891
+ auto pack_16 = _mm_packs_epi32(b, b);
1892
+ uint32_t val = _mm_cvtsi128_si32(_mm_sub_epi8(_mm_set1_epi8(0), _mm_packs_epi16(pack_16, pack_16)));
1893
+ memcpy(mem, &val, sizeof(val));
1894
+ }
1895
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 8)
1896
+ {
1897
+ auto pack_32 = _mm_packs_epi32(b, b);
1898
+ auto pack_16 = _mm_packs_epi32(pack_32, pack_32);
1899
+ uint16_t val = _mm_cvtsi128_si32(_mm_sub_epi8(_mm_set1_epi8(0), _mm_packs_epi16(pack_16, pack_16)));
1900
+ memcpy(mem, &val, sizeof(val));
1901
+ }
1902
+ else
1903
+ {
1904
+ assert(false && "unsupported arch/op combination");
1905
+ }
1906
+ }
1907
+
1908
+ XSIMD_INLINE __m128i sse_to_i(__m128 x) { return _mm_castps_si128(x); }
1909
+ XSIMD_INLINE __m128i sse_to_i(__m128d x) { return _mm_castpd_si128(x); }
1910
+ XSIMD_INLINE __m128i sse_to_i(__m128i x) { return x; }
1911
+ }
1912
+
1913
+ template <class T, class A>
1914
+ XSIMD_INLINE void store(batch_bool<T, A> b, bool* mem, requires_arch<sse2>) noexcept
1915
+ {
1916
+ detail::store_bool_sse2(detail::sse_to_i(b), mem, T {});
1917
+ }
1918
+
1919
+ // store_aligned
1920
+ template <class A>
1921
+ XSIMD_INLINE void store_aligned(float* mem, batch<float, A> const& self, requires_arch<sse2>) noexcept
1922
+ {
1923
+ return _mm_store_ps(mem, self);
1924
+ }
1925
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
1926
+ XSIMD_INLINE void store_aligned(T* mem, batch<T, A> const& self, requires_arch<sse2>) noexcept
1927
+ {
1928
+ return _mm_store_si128((__m128i*)mem, self);
1929
+ }
1930
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
1931
+ XSIMD_INLINE void store_aligned(T* mem, batch_bool<T, A> const& self, requires_arch<sse2>) noexcept
1932
+ {
1933
+ return _mm_store_si128((__m128i*)mem, self);
1934
+ }
1935
+ template <class A>
1936
+ XSIMD_INLINE void store_aligned(double* mem, batch<double, A> const& self, requires_arch<sse2>) noexcept
1937
+ {
1938
+ return _mm_store_pd(mem, self);
1939
+ }
1940
+
1941
+ // store_unaligned
1942
+ template <class A>
1943
+ XSIMD_INLINE void store_unaligned(float* mem, batch<float, A> const& self, requires_arch<sse2>) noexcept
1944
+ {
1945
+ return _mm_storeu_ps(mem, self);
1946
+ }
1947
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
1948
+ XSIMD_INLINE void store_unaligned(T* mem, batch<T, A> const& self, requires_arch<sse2>) noexcept
1949
+ {
1950
+ return _mm_storeu_si128((__m128i*)mem, self);
1951
+ }
1952
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
1953
+ XSIMD_INLINE void store_unaligned(T* mem, batch_bool<T, A> const& self, requires_arch<sse2>) noexcept
1954
+ {
1955
+ return _mm_storeu_si128((__m128i*)mem, self);
1956
+ }
1957
+ template <class A>
1958
+ XSIMD_INLINE void store_unaligned(double* mem, batch<double, A> const& self, requires_arch<sse2>) noexcept
1959
+ {
1960
+ return _mm_storeu_pd(mem, self);
1961
+ }
1962
+
1963
+ // store_stream
1964
+ template <class A>
1965
+ XSIMD_INLINE void store_stream(float* mem, batch<float, A> const& self, requires_arch<sse2>) noexcept
1966
+ {
1967
+ _mm_stream_ps(mem, self);
1968
+ }
1969
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value, void>>
1970
+ XSIMD_INLINE void store_stream(T* mem, batch<T, A> const& self, requires_arch<sse2>) noexcept
1971
+ {
1972
+ _mm_stream_si128((__m128i*)mem, self);
1973
+ }
1974
+ template <class A>
1975
+ XSIMD_INLINE void store_stream(double* mem, batch<double, A> const& self, requires_arch<sse2>) noexcept
1976
+ {
1977
+ _mm_stream_pd(mem, self);
1978
+ }
1979
+
1980
+ // sub
1981
+ template <class A>
1982
+ XSIMD_INLINE batch<float, A> sub(batch<float, A> const& self, batch<float, A> const& other, requires_arch<sse2>) noexcept
1983
+ {
1984
+ return _mm_sub_ps(self, other);
1985
+ }
1986
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
1987
+ XSIMD_INLINE batch<T, A> sub(batch<T, A> const& self, batch<T, A> const& other, requires_arch<sse2>) noexcept
1988
+ {
1989
+ XSIMD_IF_CONSTEXPR(sizeof(T) == 1)
1990
+ {
1991
+ return _mm_sub_epi8(self, other);
1992
+ }
1993
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 2)
1994
+ {
1995
+ return _mm_sub_epi16(self, other);
1996
+ }
1997
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
1998
+ {
1999
+ return _mm_sub_epi32(self, other);
2000
+ }
2001
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 8)
2002
+ {
2003
+ return _mm_sub_epi64(self, other);
2004
+ }
2005
+ else
2006
+ {
2007
+ assert(false && "unsupported arch/op combination");
2008
+ return {};
2009
+ }
2010
+ }
2011
+ template <class A>
2012
+ XSIMD_INLINE batch<double, A> sub(batch<double, A> const& self, batch<double, A> const& other, requires_arch<sse2>) noexcept
2013
+ {
2014
+ return _mm_sub_pd(self, other);
2015
+ }
2016
+
2017
+ // swizzle (constant mask)
2018
+ template <class A, uint32_t V0, uint32_t V1, uint32_t V2, uint32_t V3>
2019
+ XSIMD_INLINE batch<float, A> swizzle(batch<float, A> const& self, batch_constant<uint32_t, A, V0, V1, V2, V3>, requires_arch<sse2>) noexcept
2020
+ {
2021
+ constexpr uint32_t index = detail::shuffle(V0, V1, V2, V3);
2022
+ return _mm_shuffle_ps(self, self, index);
2023
+ }
2024
+
2025
+ template <class A, uint64_t V0, uint64_t V1>
2026
+ XSIMD_INLINE batch<double, A> swizzle(batch<double, A> const& self, batch_constant<uint64_t, A, V0, V1>, requires_arch<sse2>) noexcept
2027
+ {
2028
+ constexpr uint32_t index = detail::shuffle(V0, V1);
2029
+ return _mm_shuffle_pd(self, self, index);
2030
+ }
2031
+
2032
+ template <class A, uint64_t V0, uint64_t V1>
2033
+ XSIMD_INLINE batch<uint64_t, A> swizzle(batch<uint64_t, A> const& self, batch_constant<uint64_t, A, V0, V1>, requires_arch<sse2>) noexcept
2034
+ {
2035
+ constexpr uint32_t index = detail::shuffle(2 * V0, 2 * V0 + 1, 2 * V1, 2 * V1 + 1);
2036
+ return _mm_shuffle_epi32(self, index);
2037
+ }
2038
+
2039
+ template <class A, uint64_t V0, uint64_t V1>
2040
+ XSIMD_INLINE batch<int64_t, A> swizzle(batch<int64_t, A> const& self, batch_constant<uint64_t, A, V0, V1> mask, requires_arch<sse2>) noexcept
2041
+ {
2042
+ return bitwise_cast<int64_t>(swizzle(bitwise_cast<uint64_t>(self), mask, sse2 {}));
2043
+ }
2044
+
2045
+ template <class A, uint32_t V0, uint32_t V1, uint32_t V2, uint32_t V3>
2046
+ XSIMD_INLINE batch<uint32_t, A> swizzle(batch<uint32_t, A> const& self, batch_constant<uint32_t, A, V0, V1, V2, V3>, requires_arch<sse2>) noexcept
2047
+ {
2048
+ constexpr uint32_t index = detail::shuffle(V0, V1, V2, V3);
2049
+ return _mm_shuffle_epi32(self, index);
2050
+ }
2051
+
2052
+ template <class A, uint32_t V0, uint32_t V1, uint32_t V2, uint32_t V3>
2053
+ XSIMD_INLINE batch<int32_t, A> swizzle(batch<int32_t, A> const& self, batch_constant<uint32_t, A, V0, V1, V2, V3> mask, requires_arch<sse2>) noexcept
2054
+ {
2055
+ return bitwise_cast<int32_t>(swizzle(bitwise_cast<uint32_t>(self), mask, sse2 {}));
2056
+ }
2057
+
2058
+ template <class A, uint16_t V0, uint16_t V1, uint16_t V2, uint16_t V3, uint16_t V4, uint16_t V5, uint16_t V6, uint16_t V7>
2059
+ XSIMD_INLINE batch<uint16_t, A> swizzle(batch<uint16_t, A> const& self, batch_constant<uint16_t, A, V0, V1, V2, V3, V4, V5, V6, V7> mask, requires_arch<sse2>) noexcept
2060
+ {
2061
+ constexpr bool is_identity = detail::is_identity(mask);
2062
+ constexpr bool is_dup_lo = detail::is_dup_lo(mask);
2063
+ constexpr bool is_dup_hi = detail::is_dup_hi(mask);
2064
+
2065
+ XSIMD_IF_CONSTEXPR(is_identity)
2066
+ {
2067
+ return self;
2068
+ }
2069
+ XSIMD_IF_CONSTEXPR(is_dup_lo)
2070
+ {
2071
+ // permute the low half
2072
+ constexpr int imm = detail::mod_shuffle(V0, V1, V2, V3);
2073
+ const auto lo = _mm_shufflelo_epi16(self, imm);
2074
+ // broadcast that 64-bit low half into both halves
2075
+ const auto lo_all = _mm_unpacklo_epi64(lo, lo);
2076
+ return lo_all;
2077
+ }
2078
+ XSIMD_IF_CONSTEXPR(is_dup_hi)
2079
+ {
2080
+ // permute the high half
2081
+ constexpr int imm = detail::mod_shuffle(V4, V5, V6, V7);
2082
+ const auto hi = _mm_shufflehi_epi16(self, imm);
2083
+ // broadcast that 64-bit high half into both halves
2084
+ const auto hi_all = _mm_unpackhi_epi64(hi, hi);
2085
+ return hi_all;
2086
+ }
2087
+ // Only pick elements from the low lane
2088
+ XSIMD_IF_CONSTEXPR(detail::is_only_from_lo(mask))
2089
+ {
2090
+ // permute within each sub lane
2091
+ constexpr auto mask_lo = detail::mod_shuffle(V0, V1, V2, V3);
2092
+ constexpr auto mask_hi = detail::mod_shuffle(V4, V5, V6, V7);
2093
+ __m128i lol = _mm_shufflelo_epi16(self, mask_lo);
2094
+ __m128i loh = _mm_shufflelo_epi16(self, mask_hi);
2095
+
2096
+ // generate temporary lanes
2097
+ return _mm_unpacklo_epi64(lol, loh);
2098
+ }
2099
+ // Only pick elements from the high lane
2100
+ XSIMD_IF_CONSTEXPR(detail::is_only_from_hi(mask))
2101
+ {
2102
+ // permute within each sub lane
2103
+ constexpr auto mask_lo = detail::mod_shuffle(V0, V1, V2, V3);
2104
+ constexpr auto mask_hi = detail::mod_shuffle(V4, V5, V6, V7);
2105
+ __m128i hil = _mm_shufflehi_epi16(self, mask_lo);
2106
+ __m128i hih = _mm_shufflehi_epi16(self, mask_hi);
2107
+
2108
+ // generate temporary lanes
2109
+ return _mm_unpackhi_epi64(hil, hih);
2110
+ }
2111
+
2112
+ // Generic case
2113
+
2114
+ // permute within each sub lane
2115
+ constexpr auto mask_lo = detail::mod_shuffle(V0, V1, V2, V3);
2116
+ constexpr auto mask_hi = detail::mod_shuffle(V4, V5, V6, V7);
2117
+ __m128i lol = _mm_shufflelo_epi16(self, mask_lo);
2118
+ __m128i loh = _mm_shufflelo_epi16(self, mask_hi);
2119
+ __m128i hil = _mm_shufflehi_epi16(self, mask_lo);
2120
+ __m128i hih = _mm_shufflehi_epi16(self, mask_hi);
2121
+
2122
+ // generate temporary lanes
2123
+ __m128i lo = _mm_unpacklo_epi64(lol, loh);
2124
+ __m128i hi = _mm_unpackhi_epi64(hil, hih);
2125
+
2126
+ // mask to choose the right lane
2127
+ constexpr auto blend_mask = mask < std::integral_constant<uint16_t, 4>();
2128
+
2129
+ // blend the two permutes
2130
+ return select(blend_mask, batch<uint16_t, A>(lo), batch<uint16_t, A>(hi));
2131
+ }
2132
+
2133
+ template <class A, uint16_t V0, uint16_t V1, uint16_t V2, uint16_t V3, uint16_t V4, uint16_t V5, uint16_t V6, uint16_t V7>
2134
+ XSIMD_INLINE batch<int16_t, A> swizzle(batch<int16_t, A> const& self, batch_constant<uint16_t, A, V0, V1, V2, V3, V4, V5, V6, V7> mask, requires_arch<sse2>) noexcept
2135
+ {
2136
+ return bitwise_cast<int16_t>(swizzle(bitwise_cast<uint16_t>(self), mask, sse2 {}));
2137
+ }
2138
+
2139
+ // transpose
2140
+ template <class A>
2141
+ XSIMD_INLINE void transpose(batch<float, A>* matrix_begin, batch<float, A>* matrix_end, requires_arch<sse2>) noexcept
2142
+ {
2143
+ assert((matrix_end - matrix_begin == batch<float, A>::size) && "correctly sized matrix");
2144
+ (void)matrix_end;
2145
+ auto r0 = matrix_begin[0], r1 = matrix_begin[1], r2 = matrix_begin[2], r3 = matrix_begin[3];
2146
+ _MM_TRANSPOSE4_PS(r0, r1, r2, r3);
2147
+ matrix_begin[0] = r0;
2148
+ matrix_begin[1] = r1;
2149
+ matrix_begin[2] = r2;
2150
+ matrix_begin[3] = r3;
2151
+ }
2152
+ template <class A>
2153
+ XSIMD_INLINE void transpose(batch<uint32_t, A>* matrix_begin, batch<uint32_t, A>* matrix_end, requires_arch<sse2>) noexcept
2154
+ {
2155
+ transpose(reinterpret_cast<batch<float, A>*>(matrix_begin), reinterpret_cast<batch<float, A>*>(matrix_end), A {});
2156
+ }
2157
+ template <class A>
2158
+ XSIMD_INLINE void transpose(batch<int32_t, A>* matrix_begin, batch<int32_t, A>* matrix_end, requires_arch<sse2>) noexcept
2159
+ {
2160
+ transpose(reinterpret_cast<batch<float, A>*>(matrix_begin), reinterpret_cast<batch<float, A>*>(matrix_end), A {});
2161
+ }
2162
+
2163
+ template <class A>
2164
+ XSIMD_INLINE void transpose(batch<double, A>* matrix_begin, batch<double, A>* matrix_end, requires_arch<sse2>) noexcept
2165
+ {
2166
+ assert((matrix_end - matrix_begin == batch<double, A>::size) && "correctly sized matrix");
2167
+ (void)matrix_end;
2168
+ auto r0 = matrix_begin[0], r1 = matrix_begin[1];
2169
+ matrix_begin[0] = _mm_unpacklo_pd(r0, r1);
2170
+ matrix_begin[1] = _mm_unpackhi_pd(r0, r1);
2171
+ }
2172
+ template <class A>
2173
+ XSIMD_INLINE void transpose(batch<uint64_t, A>* matrix_begin, batch<uint64_t, A>* matrix_end, requires_arch<sse2>) noexcept
2174
+ {
2175
+ transpose(reinterpret_cast<batch<double, A>*>(matrix_begin), reinterpret_cast<batch<double, A>*>(matrix_end), A {});
2176
+ }
2177
+ template <class A>
2178
+ XSIMD_INLINE void transpose(batch<int64_t, A>* matrix_begin, batch<int64_t, A>* matrix_end, requires_arch<sse2>) noexcept
2179
+ {
2180
+ transpose(reinterpret_cast<batch<double, A>*>(matrix_begin), reinterpret_cast<batch<double, A>*>(matrix_end), A {});
2181
+ }
2182
+
2183
+ // zip_hi
2184
+ template <class A>
2185
+ XSIMD_INLINE batch<float, A> zip_hi(batch<float, A> const& self, batch<float, A> const& other, requires_arch<sse2>) noexcept
2186
+ {
2187
+ return _mm_unpackhi_ps(self, other);
2188
+ }
2189
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
2190
+ XSIMD_INLINE batch<T, A> zip_hi(batch<T, A> const& self, batch<T, A> const& other, requires_arch<sse2>) noexcept
2191
+ {
2192
+ XSIMD_IF_CONSTEXPR(sizeof(T) == 1)
2193
+ {
2194
+ return _mm_unpackhi_epi8(self, other);
2195
+ }
2196
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 2)
2197
+ {
2198
+ return _mm_unpackhi_epi16(self, other);
2199
+ }
2200
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
2201
+ {
2202
+ return _mm_unpackhi_epi32(self, other);
2203
+ }
2204
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 8)
2205
+ {
2206
+ return _mm_unpackhi_epi64(self, other);
2207
+ }
2208
+ else
2209
+ {
2210
+ assert(false && "unsupported arch/op combination");
2211
+ return {};
2212
+ }
2213
+ }
2214
+ template <class A>
2215
+ XSIMD_INLINE batch<double, A> zip_hi(batch<double, A> const& self, batch<double, A> const& other, requires_arch<sse2>) noexcept
2216
+ {
2217
+ return _mm_unpackhi_pd(self, other);
2218
+ }
2219
+
2220
+ // zip_lo
2221
+ template <class A>
2222
+ XSIMD_INLINE batch<float, A> zip_lo(batch<float, A> const& self, batch<float, A> const& other, requires_arch<sse2>) noexcept
2223
+ {
2224
+ return _mm_unpacklo_ps(self, other);
2225
+ }
2226
+ template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
2227
+ XSIMD_INLINE batch<T, A> zip_lo(batch<T, A> const& self, batch<T, A> const& other, requires_arch<sse2>) noexcept
2228
+ {
2229
+ XSIMD_IF_CONSTEXPR(sizeof(T) == 1)
2230
+ {
2231
+ return _mm_unpacklo_epi8(self, other);
2232
+ }
2233
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 2)
2234
+ {
2235
+ return _mm_unpacklo_epi16(self, other);
2236
+ }
2237
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
2238
+ {
2239
+ return _mm_unpacklo_epi32(self, other);
2240
+ }
2241
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 8)
2242
+ {
2243
+ return _mm_unpacklo_epi64(self, other);
2244
+ }
2245
+ else
2246
+ {
2247
+ assert(false && "unsupported arch/op combination");
2248
+ return {};
2249
+ }
2250
+ }
2251
+ template <class A>
2252
+ XSIMD_INLINE batch<double, A> zip_lo(batch<double, A> const& self, batch<double, A> const& other, requires_arch<sse2>) noexcept
2253
+ {
2254
+ return _mm_unpacklo_pd(self, other);
2255
+ }
2256
+
2257
+ // store_masked
2258
+ template <class A, bool... Values>
2259
+ XSIMD_INLINE void store_masked(float* mem,
2260
+ batch<float, A> const& src,
2261
+ batch_bool_constant<float, A, Values...> mask,
2262
+ aligned_mode,
2263
+ requires_arch<sse2>) noexcept
2264
+ {
2265
+ XSIMD_IF_CONSTEXPR(mask.countr_one() == 2)
2266
+ {
2267
+ _mm_storel_pi(reinterpret_cast<__m64*>(mem), src);
2268
+ }
2269
+ else XSIMD_IF_CONSTEXPR(mask.countl_one() == 2)
2270
+ {
2271
+ _mm_storeh_pi(reinterpret_cast<__m64*>(mem + 2), src);
2272
+ }
2273
+ else
2274
+ {
2275
+ store_masked<A>(mem, src, mask, requires_arch<common> {});
2276
+ }
2277
+ }
2278
+
2279
+ // get (must appear after first and swizzle so it can delegate through the xsimd API)
2280
+ namespace detail
2281
+ {
2282
+ // broadcast lane index I across a batch_constant<IdxT, A, I, I, ..., I> matching batch<T, A>::size
2283
+ template <class T, class A, size_t I, size_t... Is>
2284
+ XSIMD_INLINE auto broadcast_lane_index(std::index_sequence<Is...>) noexcept
2285
+ -> batch_constant<as_unsigned_integer_t<T>, A, static_cast<as_unsigned_integer_t<T>>(Is * 0 + I)...>
2286
+ {
2287
+ return {};
2288
+ }
2289
+
2290
+ template <class T, class A, size_t I>
2291
+ XSIMD_INLINE auto broadcast_lane_index() noexcept
2292
+ -> decltype(broadcast_lane_index<T, A, I>(std::make_index_sequence<batch<T, A>::size> {}))
2293
+ {
2294
+ return {};
2295
+ }
2296
+ }
2297
+
2298
+ template <class A, size_t I, class T>
2299
+ XSIMD_INLINE typename std::enable_if<std::is_integral<T>::value && sizeof(T) <= 2, T>::type
2300
+ get(batch<T, A> const& self, ::xsimd::index<I>, requires_arch<sse2>) noexcept
2301
+ {
2302
+ XSIMD_IF_CONSTEXPR(I == 0)
2303
+ {
2304
+ return first(self, A {});
2305
+ }
2306
+ else XSIMD_IF_CONSTEXPR(sizeof(T) == 2)
2307
+ {
2308
+ return static_cast<T>(_mm_extract_epi16(self, I));
2309
+ }
2310
+ else
2311
+ {
2312
+ // SSE2 has no pextrb; byte-lane shift + movd is the shortest path for I>0.
2313
+ return static_cast<T>(_mm_cvtsi128_si32(_mm_srli_si128(self, I)) & 0xFF);
2314
+ }
2315
+ }
2316
+
2317
+ template <class A, size_t I, class T>
2318
+ XSIMD_INLINE typename std::enable_if<(std::is_integral<T>::value && sizeof(T) >= 4) || std::is_floating_point<T>::value, T>::type
2319
+ get(batch<T, A> const& self, ::xsimd::index<I>, requires_arch<sse2>) noexcept
2320
+ {
2321
+ XSIMD_IF_CONSTEXPR(I == 0)
2322
+ {
2323
+ return first(self, A {});
2324
+ }
2325
+ else
2326
+ {
2327
+ return first(swizzle(self, detail::broadcast_lane_index<T, A, I>(), A {}), A {});
2328
+ }
2329
+ }
2330
+ }
2331
+ }
2332
+
2333
+ #endif