react-native-executorch 0.10.6 → 0.10.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (237) hide show
  1. package/lib/module/fetcher/telemetry.js +1 -1
  2. package/package.json +1 -1
  3. package/react-native-executorch.podspec +2 -0
  4. package/src/fetcher/telemetry.ts +1 -1
  5. package/third-party/common/phonemis/CMakeLists.txt +70 -14
  6. package/third-party/common/phonemis/README.md +183 -33
  7. package/third-party/common/phonemis/THIRD_PARTY_NOTICES.md +57 -0
  8. package/third-party/common/phonemis/knowledge/code_style.md +642 -0
  9. package/third-party/common/phonemis/licenses/Unicode-3.0.txt +39 -0
  10. package/third-party/common/phonemis/licenses/misaki-Apache-2.0.txt +201 -0
  11. package/third-party/common/phonemis/licenses/nlohmann-json-MIT.txt +21 -0
  12. package/third-party/common/phonemis/licenses/xsimd-BSD-3-Clause.txt +29 -0
  13. package/third-party/common/phonemis/src/phonemis/base/config.h +6 -0
  14. package/third-party/common/phonemis/src/phonemis/base/ipipeline.cpp +75 -0
  15. package/third-party/common/phonemis/src/phonemis/base/ipipeline.h +21 -0
  16. package/third-party/common/phonemis/src/phonemis/base/phonemizer/constants.h +2 -5
  17. package/third-party/common/phonemis/src/phonemis/base/phonemizer/lexicon_phonemizer.cpp +3 -4
  18. package/third-party/common/phonemis/src/phonemis/base/phonemizer/nn/neural_phonemizer.cpp +17 -8
  19. package/third-party/common/phonemis/src/phonemis/base/phonemizer/nn/neural_phonemizer.h +4 -0
  20. package/third-party/common/phonemis/src/phonemis/base/phonemizer/nn/tokenizer.cpp +21 -6
  21. package/third-party/common/phonemis/src/phonemis/base/phonemizer/nn/tokenizer.h +13 -4
  22. package/third-party/common/phonemis/src/phonemis/base/pipeline.cpp +8 -0
  23. package/third-party/common/phonemis/src/phonemis/base/pipeline.h +19 -0
  24. package/third-party/common/phonemis/src/phonemis/base/processor/common/conditions.cpp +37 -0
  25. package/third-party/common/phonemis/src/phonemis/base/processor/common/conditions.h +45 -0
  26. package/third-party/common/phonemis/src/phonemis/base/processor/common/constants.h +10 -0
  27. package/third-party/common/phonemis/src/phonemis/base/processor/common/context.cpp +105 -0
  28. package/third-party/common/phonemis/src/phonemis/base/processor/common/context.h +49 -0
  29. package/third-party/common/phonemis/src/phonemis/base/processor/common/document.cpp +173 -0
  30. package/third-party/common/phonemis/src/phonemis/base/processor/common/document.h +67 -0
  31. package/third-party/common/phonemis/src/phonemis/base/processor/common/text.cpp +75 -0
  32. package/third-party/common/phonemis/src/phonemis/base/processor/common/text.h +60 -0
  33. package/third-party/common/phonemis/src/phonemis/base/processor/common/types.h +18 -0
  34. package/third-party/common/phonemis/src/phonemis/base/processor/config.h +53 -0
  35. package/third-party/common/phonemis/src/phonemis/base/processor/layer.h +9 -7
  36. package/third-party/common/phonemis/src/phonemis/base/processor/layers/normalize/constants.h +20 -0
  37. package/third-party/common/phonemis/src/phonemis/base/processor/layers/normalize/layer.cpp +89 -0
  38. package/third-party/common/phonemis/src/phonemis/base/processor/layers/normalize/layer.h +35 -0
  39. package/third-party/common/phonemis/src/phonemis/base/processor/layers/normalize/types.h +16 -0
  40. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/kind.h +40 -0
  41. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/layer.h +382 -0
  42. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/notation.h +30 -0
  43. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/numerals.cpp +51 -0
  44. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/numerals.h +31 -0
  45. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/pattern.h +30 -0
  46. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/pattern_set.cpp +17 -0
  47. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/pattern_set.h +31 -0
  48. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/patterns.cpp +811 -0
  49. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/patterns.h +285 -0
  50. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/primitives.cpp +64 -0
  51. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/primitives.h +23 -0
  52. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/types.h +94 -0
  53. package/third-party/common/phonemis/src/phonemis/base/processor/layers/sanitizer/layer.cpp +19 -0
  54. package/third-party/common/phonemis/src/phonemis/base/processor/{sanitizer_layer.h → layers/sanitizer/layer.h} +8 -8
  55. package/third-party/common/phonemis/src/phonemis/base/processor/layers/sym2word/layer.cpp +65 -0
  56. package/third-party/common/phonemis/src/phonemis/base/processor/layers/sym2word/layer.h +29 -0
  57. package/third-party/common/phonemis/src/phonemis/base/processor/layers/term2word/layer.cpp +170 -0
  58. package/third-party/common/phonemis/src/phonemis/base/processor/layers/term2word/layer.h +40 -0
  59. package/third-party/common/phonemis/src/phonemis/base/processor/layers/term2word/types.h +25 -0
  60. package/third-party/common/phonemis/src/phonemis/base/processor/layers/trim/layer.cpp +47 -0
  61. package/third-party/common/phonemis/src/phonemis/base/processor/layers/trim/layer.h +19 -0
  62. package/third-party/common/phonemis/src/phonemis/base/processor/preprocessor.cpp +60 -0
  63. package/third-party/common/phonemis/src/phonemis/base/processor/preprocessor.h +45 -0
  64. package/third-party/common/phonemis/src/phonemis/base/processor/processor.cpp +6 -7
  65. package/third-party/common/phonemis/src/phonemis/base/processor/processor.h +14 -10
  66. package/third-party/common/phonemis/src/phonemis/base/tagger/hmm_tagger.cpp +89 -52
  67. package/third-party/common/phonemis/src/phonemis/base/tagger/hmm_tagger.h +16 -9
  68. package/third-party/common/phonemis/src/phonemis/base/tokenizer/tokenizer.cpp +13 -12
  69. package/third-party/common/phonemis/src/phonemis/lang/de/constants.h +183 -19
  70. package/third-party/common/phonemis/src/phonemis/lang/de/num2word.cpp +355 -309
  71. package/third-party/common/phonemis/src/phonemis/lang/de/num2word.h +42 -17
  72. package/third-party/common/phonemis/src/phonemis/lang/de/patterns.cpp +56 -0
  73. package/third-party/common/phonemis/src/phonemis/lang/de/patterns.h +15 -0
  74. package/third-party/common/phonemis/src/phonemis/lang/de/pipeline.h +3 -3
  75. package/third-party/common/phonemis/src/phonemis/lang/en/constants.h +181 -30
  76. package/third-party/common/phonemis/src/phonemis/lang/en/hmm_tagger.cpp +5 -7
  77. package/third-party/common/phonemis/src/phonemis/lang/en/num2word.cpp +232 -135
  78. package/third-party/common/phonemis/src/phonemis/lang/en/num2word.h +41 -16
  79. package/third-party/common/phonemis/src/phonemis/lang/en/pipeline.h +3 -10
  80. package/third-party/common/phonemis/src/phonemis/lang/es/constants.h +182 -60
  81. package/third-party/common/phonemis/src/phonemis/lang/es/num2word.cpp +247 -212
  82. package/third-party/common/phonemis/src/phonemis/lang/es/num2word.h +38 -18
  83. package/third-party/common/phonemis/src/phonemis/lang/es/patterns.cpp +50 -0
  84. package/third-party/common/phonemis/src/phonemis/lang/es/patterns.h +15 -0
  85. package/third-party/common/phonemis/src/phonemis/lang/es/pipeline.h +3 -3
  86. package/third-party/common/phonemis/src/phonemis/lang/fr/constants.h +152 -26
  87. package/third-party/common/phonemis/src/phonemis/lang/fr/num2word.cpp +252 -179
  88. package/third-party/common/phonemis/src/phonemis/lang/fr/num2word.h +38 -15
  89. package/third-party/common/phonemis/src/phonemis/lang/fr/patterns.cpp +83 -0
  90. package/third-party/common/phonemis/src/phonemis/lang/fr/patterns.h +15 -0
  91. package/third-party/common/phonemis/src/phonemis/lang/fr/pipeline.h +3 -3
  92. package/third-party/common/phonemis/src/phonemis/lang/hi/constants.h +62 -10
  93. package/third-party/common/phonemis/src/phonemis/lang/hi/num2word.cpp +74 -123
  94. package/third-party/common/phonemis/src/phonemis/lang/hi/num2word.h +27 -16
  95. package/third-party/common/phonemis/src/phonemis/lang/hi/pipeline.h +5 -3
  96. package/third-party/common/phonemis/src/phonemis/lang/it/constants.h +122 -42
  97. package/third-party/common/phonemis/src/phonemis/lang/it/num2word.cpp +200 -207
  98. package/third-party/common/phonemis/src/phonemis/lang/it/num2word.h +30 -18
  99. package/third-party/common/phonemis/src/phonemis/lang/it/patterns.cpp +25 -0
  100. package/third-party/common/phonemis/src/phonemis/lang/it/patterns.h +15 -0
  101. package/third-party/common/phonemis/src/phonemis/lang/it/pipeline.h +3 -3
  102. package/third-party/common/phonemis/src/phonemis/lang/pl/constants.h +346 -77
  103. package/third-party/common/phonemis/src/phonemis/lang/pl/num2word.cpp +631 -246
  104. package/third-party/common/phonemis/src/phonemis/lang/pl/num2word.h +47 -15
  105. package/third-party/common/phonemis/src/phonemis/lang/pl/pipeline.h +6 -6
  106. package/third-party/common/phonemis/src/phonemis/lang/pt/constants.h +201 -0
  107. package/third-party/common/phonemis/src/phonemis/lang/pt/num2word.cpp +365 -0
  108. package/third-party/common/phonemis/src/phonemis/lang/pt/num2word.h +53 -0
  109. package/third-party/common/phonemis/src/phonemis/lang/pt/pipeline.h +4 -2
  110. package/third-party/common/phonemis/src/phonemis/main.cpp +42 -11
  111. package/third-party/common/phonemis/src/phonemis/protophone/meta.h +24 -0
  112. package/third-party/common/phonemis/src/phonemis/protophone/numeric.h +26 -0
  113. package/third-party/common/phonemis/src/phonemis/protophone/protophone.cpp +525 -0
  114. package/third-party/common/phonemis/src/phonemis/protophone/protophone.h +80 -0
  115. package/third-party/common/phonemis/src/phonemis/protophone/tensor.h +76 -0
  116. package/third-party/common/phonemis/src/phonemis/protophone/tensor_utils.h +89 -0
  117. package/third-party/common/phonemis/src/phonemis/protophone/tensor_view.h +125 -0
  118. package/third-party/common/phonemis/src/phonemis/protophone/types.h +43 -0
  119. package/third-party/common/phonemis/src/phonemis/utils/strings.h +20 -14
  120. package/third-party/common/phonemis/src/phonemis/utils/unicode.h +15 -1
  121. package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_arithmetic.hpp +267 -0
  122. package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_bit.hpp +232 -0
  123. package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_cast.hpp +43 -0
  124. package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_complex.hpp +112 -0
  125. package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_details.hpp +386 -0
  126. package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_logical.hpp +240 -0
  127. package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_math.hpp +2601 -0
  128. package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_memory.hpp +1006 -0
  129. package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_rounding.hpp +72 -0
  130. package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_swizzle.hpp +260 -0
  131. package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_trigo.hpp +996 -0
  132. package/third-party/common/phonemis/src/third-party/xsimd/arch/utils/shifts.hpp +82 -0
  133. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx.hpp +2111 -0
  134. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx2.hpp +1591 -0
  135. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx2_128.hpp +170 -0
  136. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512bw.hpp +724 -0
  137. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512cd.hpp +28 -0
  138. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512dq.hpp +270 -0
  139. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512er.hpp +17 -0
  140. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512f.hpp +2919 -0
  141. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512ifma.hpp +17 -0
  142. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512pf.hpp +17 -0
  143. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512vbmi.hpp +76 -0
  144. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512vbmi2.hpp +130 -0
  145. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512vnni_avx512bw.hpp +17 -0
  146. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512vnni_avx512vbmi2.hpp +17 -0
  147. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx_128.hpp +164 -0
  148. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avxvnni.hpp +17 -0
  149. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_common.hpp +26 -0
  150. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_common_fwd.hpp +127 -0
  151. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_constants.hpp +393 -0
  152. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_emulated.hpp +787 -0
  153. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_fma3_avx.hpp +93 -0
  154. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_fma3_avx2.hpp +46 -0
  155. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_fma3_sse.hpp +97 -0
  156. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_fma4.hpp +92 -0
  157. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_i8mm_neon64.hpp +17 -0
  158. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_isa.hpp +148 -0
  159. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_neon.hpp +3580 -0
  160. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_neon64.hpp +1614 -0
  161. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_rvv.hpp +1515 -0
  162. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_scalar.hpp +1210 -0
  163. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_sse2.hpp +2333 -0
  164. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_sse3.hpp +66 -0
  165. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_sse4_1.hpp +510 -0
  166. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_sse4_2.hpp +44 -0
  167. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_ssse3.hpp +186 -0
  168. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_sve.hpp +1186 -0
  169. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_vsx.hpp +947 -0
  170. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_vxe.hpp +787 -0
  171. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_wasm.hpp +1819 -0
  172. package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_arch.hpp +242 -0
  173. package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_config.hpp +633 -0
  174. package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_cpu_features.hpp +50 -0
  175. package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_cpu_features_arm.hpp +132 -0
  176. package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_cpu_features_ppc.hpp +54 -0
  177. package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_cpu_features_riscv.hpp +95 -0
  178. package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_cpu_features_s390x.hpp +56 -0
  179. package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_cpu_features_x86.hpp +1121 -0
  180. package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_cpuid.hpp +144 -0
  181. package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_getauxval.hpp +159 -0
  182. package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_macros.hpp +78 -0
  183. package/third-party/common/phonemis/src/third-party/xsimd/math/xsimd_rem_pio2.hpp +707 -0
  184. package/third-party/common/phonemis/src/third-party/xsimd/memory/xsimd_aligned_allocator.hpp +349 -0
  185. package/third-party/common/phonemis/src/third-party/xsimd/memory/xsimd_alignment.hpp +102 -0
  186. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_all_registers.hpp +57 -0
  187. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_api.hpp +3106 -0
  188. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx2_register.hpp +57 -0
  189. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512bw_register.hpp +51 -0
  190. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512cd_register.hpp +51 -0
  191. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512dq_register.hpp +51 -0
  192. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512er_register.hpp +51 -0
  193. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512f_register.hpp +77 -0
  194. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512ifma_register.hpp +51 -0
  195. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512pf_register.hpp +51 -0
  196. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512vbmi2_register.hpp +51 -0
  197. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512vbmi_register.hpp +51 -0
  198. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512vnni_avx512bw_register.hpp +54 -0
  199. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512vnni_avx512vbmi2_register.hpp +53 -0
  200. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx_register.hpp +79 -0
  201. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avxvnni_register.hpp +44 -0
  202. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_batch.hpp +1666 -0
  203. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_batch_constant.hpp +572 -0
  204. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_batch_fwd.hpp +41 -0
  205. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_common_arch.hpp +49 -0
  206. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_emulated_register.hpp +80 -0
  207. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_fma3_avx2_register.hpp +50 -0
  208. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_fma3_avx_register.hpp +50 -0
  209. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_fma3_sse_register.hpp +50 -0
  210. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_fma4_register.hpp +50 -0
  211. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_i8mm_neon64_register.hpp +55 -0
  212. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_neon64_register.hpp +55 -0
  213. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_neon_register.hpp +130 -0
  214. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_register.hpp +96 -0
  215. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_rvv_register.hpp +491 -0
  216. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_sse2_register.hpp +59 -0
  217. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_sse3_register.hpp +49 -0
  218. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_sse4_1_register.hpp +48 -0
  219. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_sse4_2_register.hpp +48 -0
  220. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_ssse3_register.hpp +48 -0
  221. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_sve_register.hpp +216 -0
  222. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_traits.hpp +409 -0
  223. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_utils.hpp +462 -0
  224. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_vsx_register.hpp +84 -0
  225. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_vxe_register.hpp +86 -0
  226. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_wasm_register.hpp +59 -0
  227. package/third-party/common/phonemis/src/third-party/xsimd/utils/bits.hpp +122 -0
  228. package/third-party/common/phonemis/src/third-party/xsimd/utils/xsimd_type_traits.hpp +145 -0
  229. package/third-party/common/phonemis/src/third-party/xsimd/xsimd.hpp +43 -0
  230. package/third-party/common/phonemis/src/phonemis/base/processor/constants.h +0 -11
  231. package/third-party/common/phonemis/src/phonemis/base/processor/num2word/config.h +0 -16
  232. package/third-party/common/phonemis/src/phonemis/base/processor/num2word/layer.cpp +0 -271
  233. package/third-party/common/phonemis/src/phonemis/base/processor/num2word/layer.h +0 -45
  234. package/third-party/common/phonemis/src/phonemis/base/processor/num2word/types.h +0 -29
  235. package/third-party/common/phonemis/src/phonemis/base/processor/sanitizer_layer.cpp +0 -22
  236. package/third-party/common/phonemis/src/phonemis/base/processor/trim_layer.cpp +0 -40
  237. package/third-party/common/phonemis/src/phonemis/base/processor/trim_layer.h +0 -22
@@ -0,0 +1,3580 @@
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_NEON_HPP
13
+ #define XSIMD_NEON_HPP
14
+
15
+ #include <algorithm>
16
+ #include <array>
17
+ #include <cassert>
18
+ #include <complex>
19
+ #include <type_traits>
20
+
21
+ #include "../types/xsimd_batch_fwd.hpp"
22
+ #include "../types/xsimd_neon_register.hpp"
23
+ #include "../types/xsimd_utils.hpp"
24
+ #include "../utils/xsimd_type_traits.hpp"
25
+ #include "./common/xsimd_common_bit.hpp"
26
+ #include "./common/xsimd_common_cast.hpp"
27
+ #include "./xsimd_common_fwd.hpp"
28
+
29
+ namespace xsimd
30
+ {
31
+ namespace kernel
32
+ {
33
+ using namespace types;
34
+
35
+ namespace detail
36
+ {
37
+ /**************************************
38
+ * enabling / disabling metafunctions *
39
+ **************************************/
40
+
41
+ template <class T>
42
+ using enable_neon_type_t = std::enable_if_t<std::is_integral<T>::value || std::is_same<T, float>::value,
43
+ int>;
44
+
45
+ template <class T>
46
+ using exclude_int64_neon_t
47
+ = std::enable_if_t<(std::is_integral<T>::value && sizeof(T) != 8) || std::is_same<T, float>::value, int>;
48
+ }
49
+
50
+ /****************
51
+ * bitwise_cast *
52
+ ****************/
53
+
54
+ namespace wrap
55
+ {
56
+ // TODO(c++17): Make a single function with if constexpr switch
57
+ // Templating on the scalar type `T` is required because in some compilers (e.g. MSVC)
58
+ // the vector types are all aliases of the same type.
59
+ template <class R, class T, std::enable_if_t<std::is_same<R, uint8_t>::value && std::is_same<T, uint8_t>::value, int> = 0>
60
+ XSIMD_INLINE uint8x16_t x_vreinterpretq(uint8x16_t a) noexcept { return a; }
61
+ template <class R, class T, std::enable_if_t<std::is_same<R, uint8_t>::value && std::is_same<T, int8_t>::value, int> = 0>
62
+ XSIMD_INLINE uint8x16_t x_vreinterpretq(int8x16_t a) noexcept { return vreinterpretq_u8_s8(a); }
63
+ template <class R, class T, std::enable_if_t<std::is_same<R, uint8_t>::value && std::is_same<T, uint16_t>::value, int> = 0>
64
+ XSIMD_INLINE uint8x16_t x_vreinterpretq(uint16x8_t a) noexcept { return vreinterpretq_u8_u16(a); }
65
+ template <class R, class T, std::enable_if_t<std::is_same<R, uint8_t>::value && std::is_same<T, int16_t>::value, int> = 0>
66
+ XSIMD_INLINE uint8x16_t x_vreinterpretq(int16x8_t a) noexcept { return vreinterpretq_u8_s16(a); }
67
+ template <class R, class T, std::enable_if_t<std::is_same<R, uint8_t>::value && std::is_same<T, uint32_t>::value, int> = 0>
68
+ XSIMD_INLINE uint8x16_t x_vreinterpretq(uint32x4_t a) noexcept { return vreinterpretq_u8_u32(a); }
69
+ template <class R, class T, std::enable_if_t<std::is_same<R, uint8_t>::value && std::is_same<T, int32_t>::value, int> = 0>
70
+ XSIMD_INLINE uint8x16_t x_vreinterpretq(int32x4_t a) noexcept { return vreinterpretq_u8_s32(a); }
71
+ template <class R, class T, std::enable_if_t<std::is_same<R, uint8_t>::value && std::is_same<T, uint64_t>::value, int> = 0>
72
+ XSIMD_INLINE uint8x16_t x_vreinterpretq(uint64x2_t a) noexcept { return vreinterpretq_u8_u64(a); }
73
+ template <class R, class T, std::enable_if_t<std::is_same<R, uint8_t>::value && std::is_same<T, int64_t>::value, int> = 0>
74
+ XSIMD_INLINE uint8x16_t x_vreinterpretq(int64x2_t a) noexcept { return vreinterpretq_u8_s64(a); }
75
+ template <class R, class T, std::enable_if_t<std::is_same<R, uint8_t>::value && std::is_same<T, float>::value, int> = 0>
76
+ XSIMD_INLINE uint8x16_t x_vreinterpretq(float32x4_t a) noexcept { return vreinterpretq_u8_f32(a); }
77
+
78
+ // TODO(c++17): Make a single function with if constexpr switch
79
+ // Templating on the scalar type `T` is required because in some compilers (e.g. MSVC)
80
+ // the vector types are all aliases of the same type.
81
+ template <class R, class T, std::enable_if_t<std::is_same<R, int8_t>::value && std::is_same<T, uint8_t>::value, int> = 0>
82
+ XSIMD_INLINE int8x16_t x_vreinterpretq(uint8x16_t a) noexcept { return vreinterpretq_s8_u8(a); }
83
+ template <class R, class T, std::enable_if_t<std::is_same<R, int8_t>::value && std::is_same<T, int8_t>::value, int> = 0>
84
+ XSIMD_INLINE int8x16_t x_vreinterpretq(int8x16_t a) noexcept { return a; }
85
+ template <class R, class T, std::enable_if_t<std::is_same<R, int8_t>::value && std::is_same<T, uint16_t>::value, int> = 0>
86
+ XSIMD_INLINE int8x16_t x_vreinterpretq(uint16x8_t a) noexcept { return vreinterpretq_s8_u16(a); }
87
+ template <class R, class T, std::enable_if_t<std::is_same<R, int8_t>::value && std::is_same<T, int16_t>::value, int> = 0>
88
+ XSIMD_INLINE int8x16_t x_vreinterpretq(int16x8_t a) noexcept { return vreinterpretq_s8_s16(a); }
89
+ template <class R, class T, std::enable_if_t<std::is_same<R, int8_t>::value && std::is_same<T, uint32_t>::value, int> = 0>
90
+ XSIMD_INLINE int8x16_t x_vreinterpretq(uint32x4_t a) noexcept { return vreinterpretq_s8_u32(a); }
91
+ template <class R, class T, std::enable_if_t<std::is_same<R, int8_t>::value && std::is_same<T, int32_t>::value, int> = 0>
92
+ XSIMD_INLINE int8x16_t x_vreinterpretq(int32x4_t a) noexcept { return vreinterpretq_s8_s32(a); }
93
+ template <class R, class T, std::enable_if_t<std::is_same<R, int8_t>::value && std::is_same<T, uint64_t>::value, int> = 0>
94
+ XSIMD_INLINE int8x16_t x_vreinterpretq(uint64x2_t a) noexcept { return vreinterpretq_s8_u64(a); }
95
+ template <class R, class T, std::enable_if_t<std::is_same<R, int8_t>::value && std::is_same<T, int64_t>::value, int> = 0>
96
+ XSIMD_INLINE int8x16_t x_vreinterpretq(int64x2_t a) noexcept { return vreinterpretq_s8_s64(a); }
97
+ template <class R, class T, std::enable_if_t<std::is_same<R, int8_t>::value && std::is_same<T, float>::value, int> = 0>
98
+ XSIMD_INLINE int8x16_t x_vreinterpretq(float32x4_t a) noexcept { return vreinterpretq_s8_f32(a); }
99
+
100
+ // TODO(c++17): Make a single function with if constexpr switch
101
+ // Templating on the scalar type `T` is required because in some compilers (e.g. MSVC)
102
+ // the vector types are all aliases of the same type.
103
+ template <class R, class T, std::enable_if_t<std::is_same<R, uint16_t>::value && std::is_same<T, uint8_t>::value, int> = 0>
104
+ XSIMD_INLINE uint16x8_t x_vreinterpretq(uint8x16_t a) noexcept { return vreinterpretq_u16_u8(a); }
105
+ template <class R, class T, std::enable_if_t<std::is_same<R, uint16_t>::value && std::is_same<T, int8_t>::value, int> = 0>
106
+ XSIMD_INLINE uint16x8_t x_vreinterpretq(int8x16_t a) noexcept { return vreinterpretq_u16_s8(a); }
107
+ template <class R, class T, std::enable_if_t<std::is_same<R, uint16_t>::value && std::is_same<T, uint16_t>::value, int> = 0>
108
+ XSIMD_INLINE uint16x8_t x_vreinterpretq(uint16x8_t a) noexcept { return a; }
109
+ template <class R, class T, std::enable_if_t<std::is_same<R, uint16_t>::value && std::is_same<T, int16_t>::value, int> = 0>
110
+ XSIMD_INLINE uint16x8_t x_vreinterpretq(int16x8_t a) noexcept { return vreinterpretq_u16_s16(a); }
111
+ template <class R, class T, std::enable_if_t<std::is_same<R, uint16_t>::value && std::is_same<T, uint32_t>::value, int> = 0>
112
+ XSIMD_INLINE uint16x8_t x_vreinterpretq(uint32x4_t a) noexcept { return vreinterpretq_u16_u32(a); }
113
+ template <class R, class T, std::enable_if_t<std::is_same<R, uint16_t>::value && std::is_same<T, int32_t>::value, int> = 0>
114
+ XSIMD_INLINE uint16x8_t x_vreinterpretq(int32x4_t a) noexcept { return vreinterpretq_u16_s32(a); }
115
+ template <class R, class T, std::enable_if_t<std::is_same<R, uint16_t>::value && std::is_same<T, uint64_t>::value, int> = 0>
116
+ XSIMD_INLINE uint16x8_t x_vreinterpretq(uint64x2_t a) noexcept { return vreinterpretq_u16_u64(a); }
117
+ template <class R, class T, std::enable_if_t<std::is_same<R, uint16_t>::value && std::is_same<T, int64_t>::value, int> = 0>
118
+ XSIMD_INLINE uint16x8_t x_vreinterpretq(int64x2_t a) noexcept { return vreinterpretq_u16_s64(a); }
119
+ template <class R, class T, std::enable_if_t<std::is_same<R, uint16_t>::value && std::is_same<T, float>::value, int> = 0>
120
+ XSIMD_INLINE uint16x8_t x_vreinterpretq(float32x4_t a) noexcept { return vreinterpretq_u16_f32(a); }
121
+
122
+ // TODO(c++17): Make a single function with if constexpr switch
123
+ // Templating on the scalar type `T` is required because in some compilers (e.g. MSVC)
124
+ // the vector types are all aliases of the same type.
125
+ template <class R, class T, std::enable_if_t<std::is_same<R, int16_t>::value && std::is_same<T, uint8_t>::value, int> = 0>
126
+ XSIMD_INLINE int16x8_t x_vreinterpretq(uint8x16_t a) noexcept { return vreinterpretq_s16_u8(a); }
127
+ template <class R, class T, std::enable_if_t<std::is_same<R, int16_t>::value && std::is_same<T, int8_t>::value, int> = 0>
128
+ XSIMD_INLINE int16x8_t x_vreinterpretq(int8x16_t a) noexcept { return vreinterpretq_s16_s8(a); }
129
+ template <class R, class T, std::enable_if_t<std::is_same<R, int16_t>::value && std::is_same<T, uint16_t>::value, int> = 0>
130
+ XSIMD_INLINE int16x8_t x_vreinterpretq(uint16x8_t a) noexcept { return vreinterpretq_s16_u16(a); }
131
+ template <class R, class T, std::enable_if_t<std::is_same<R, int16_t>::value && std::is_same<T, int16_t>::value, int> = 0>
132
+ XSIMD_INLINE int16x8_t x_vreinterpretq(int16x8_t a) noexcept { return a; }
133
+ template <class R, class T, std::enable_if_t<std::is_same<R, int16_t>::value && std::is_same<T, uint32_t>::value, int> = 0>
134
+ XSIMD_INLINE int16x8_t x_vreinterpretq(uint32x4_t a) noexcept { return vreinterpretq_s16_u32(a); }
135
+ template <class R, class T, std::enable_if_t<std::is_same<R, int16_t>::value && std::is_same<T, int32_t>::value, int> = 0>
136
+ XSIMD_INLINE int16x8_t x_vreinterpretq(int32x4_t a) noexcept { return vreinterpretq_s16_s32(a); }
137
+ template <class R, class T, std::enable_if_t<std::is_same<R, int16_t>::value && std::is_same<T, uint64_t>::value, int> = 0>
138
+ XSIMD_INLINE int16x8_t x_vreinterpretq(uint64x2_t a) noexcept { return vreinterpretq_s16_u64(a); }
139
+ template <class R, class T, std::enable_if_t<std::is_same<R, int16_t>::value && std::is_same<T, int64_t>::value, int> = 0>
140
+ XSIMD_INLINE int16x8_t x_vreinterpretq(int64x2_t a) noexcept { return vreinterpretq_s16_s64(a); }
141
+ template <class R, class T, std::enable_if_t<std::is_same<R, int16_t>::value && std::is_same<T, float>::value, int> = 0>
142
+ XSIMD_INLINE int16x8_t x_vreinterpretq(float32x4_t a) noexcept { return vreinterpretq_s16_f32(a); }
143
+
144
+ // TODO(c++17): Make a single function with if constexpr switch
145
+ // Templating on the scalar type `T` is required because in some compilers (e.g. MSVC)
146
+ // the vector types are all aliases of the same type.
147
+ template <class R, class T, std::enable_if_t<std::is_same<R, uint32_t>::value && std::is_same<T, uint8_t>::value, int> = 0>
148
+ XSIMD_INLINE uint32x4_t x_vreinterpretq(uint8x16_t a) noexcept { return vreinterpretq_u32_u8(a); }
149
+ template <class R, class T, std::enable_if_t<std::is_same<R, uint32_t>::value && std::is_same<T, int8_t>::value, int> = 0>
150
+ XSIMD_INLINE uint32x4_t x_vreinterpretq(int8x16_t a) noexcept { return vreinterpretq_u32_s8(a); }
151
+ template <class R, class T, std::enable_if_t<std::is_same<R, uint32_t>::value && std::is_same<T, uint16_t>::value, int> = 0>
152
+ XSIMD_INLINE uint32x4_t x_vreinterpretq(uint16x8_t a) noexcept { return vreinterpretq_u32_u16(a); }
153
+ template <class R, class T, std::enable_if_t<std::is_same<R, uint32_t>::value && std::is_same<T, int16_t>::value, int> = 0>
154
+ XSIMD_INLINE uint32x4_t x_vreinterpretq(int16x8_t a) noexcept { return vreinterpretq_u32_s16(a); }
155
+ template <class R, class T, std::enable_if_t<std::is_same<R, uint32_t>::value && std::is_same<T, uint32_t>::value, int> = 0>
156
+ XSIMD_INLINE uint32x4_t x_vreinterpretq(uint32x4_t a) noexcept { return a; }
157
+ template <class R, class T, std::enable_if_t<std::is_same<R, uint32_t>::value && std::is_same<T, int32_t>::value, int> = 0>
158
+ XSIMD_INLINE uint32x4_t x_vreinterpretq(int32x4_t a) noexcept { return vreinterpretq_u32_s32(a); }
159
+ template <class R, class T, std::enable_if_t<std::is_same<R, uint32_t>::value && std::is_same<T, uint64_t>::value, int> = 0>
160
+ XSIMD_INLINE uint32x4_t x_vreinterpretq(uint64x2_t a) noexcept { return vreinterpretq_u32_u64(a); }
161
+ template <class R, class T, std::enable_if_t<std::is_same<R, uint32_t>::value && std::is_same<T, int64_t>::value, int> = 0>
162
+ XSIMD_INLINE uint32x4_t x_vreinterpretq(int64x2_t a) noexcept { return vreinterpretq_u32_s64(a); }
163
+ template <class R, class T, std::enable_if_t<std::is_same<R, uint32_t>::value && std::is_same<T, float>::value, int> = 0>
164
+ XSIMD_INLINE uint32x4_t x_vreinterpretq(float32x4_t a) noexcept { return vreinterpretq_u32_f32(a); }
165
+
166
+ // TODO(c++17): Make a single function with if constexpr switch
167
+ // Templating on the scalar type `T` is required because in some compilers (e.g. MSVC)
168
+ // the vector types are all aliases of the same type.
169
+ template <class R, class T, std::enable_if_t<std::is_same<R, int32_t>::value && std::is_same<T, uint8_t>::value, int> = 0>
170
+ XSIMD_INLINE int32x4_t x_vreinterpretq(uint8x16_t a) noexcept { return vreinterpretq_s32_u8(a); }
171
+ template <class R, class T, std::enable_if_t<std::is_same<R, int32_t>::value && std::is_same<T, int8_t>::value, int> = 0>
172
+ XSIMD_INLINE int32x4_t x_vreinterpretq(int8x16_t a) noexcept { return vreinterpretq_s32_s8(a); }
173
+ template <class R, class T, std::enable_if_t<std::is_same<R, int32_t>::value && std::is_same<T, uint16_t>::value, int> = 0>
174
+ XSIMD_INLINE int32x4_t x_vreinterpretq(uint16x8_t a) noexcept { return vreinterpretq_s32_u16(a); }
175
+ template <class R, class T, std::enable_if_t<std::is_same<R, int32_t>::value && std::is_same<T, int16_t>::value, int> = 0>
176
+ XSIMD_INLINE int32x4_t x_vreinterpretq(int16x8_t a) noexcept { return vreinterpretq_s32_s16(a); }
177
+ template <class R, class T, std::enable_if_t<std::is_same<R, int32_t>::value && std::is_same<T, uint32_t>::value, int> = 0>
178
+ XSIMD_INLINE int32x4_t x_vreinterpretq(uint32x4_t a) noexcept { return vreinterpretq_s32_u32(a); }
179
+ template <class R, class T, std::enable_if_t<std::is_same<R, int32_t>::value && std::is_same<T, int32_t>::value, int> = 0>
180
+ XSIMD_INLINE int32x4_t x_vreinterpretq(int32x4_t a) noexcept { return a; }
181
+ template <class R, class T, std::enable_if_t<std::is_same<R, int32_t>::value && std::is_same<T, uint64_t>::value, int> = 0>
182
+ XSIMD_INLINE int32x4_t x_vreinterpretq(uint64x2_t a) noexcept { return vreinterpretq_s32_u64(a); }
183
+ template <class R, class T, std::enable_if_t<std::is_same<R, int32_t>::value && std::is_same<T, int64_t>::value, int> = 0>
184
+ XSIMD_INLINE int32x4_t x_vreinterpretq(int64x2_t a) noexcept { return vreinterpretq_s32_s64(a); }
185
+ template <class R, class T, std::enable_if_t<std::is_same<R, int32_t>::value && std::is_same<T, float>::value, int> = 0>
186
+ XSIMD_INLINE int32x4_t x_vreinterpretq(float32x4_t a) noexcept { return vreinterpretq_s32_f32(a); }
187
+
188
+ // TODO(c++17): Make a single function with if constexpr switch
189
+ // Templating on the scalar type `T` is required because in some compilers (e.g. MSVC)
190
+ // the vector types are all aliases of the same type.
191
+ template <class R, class T, std::enable_if_t<std::is_same<R, uint64_t>::value && std::is_same<T, uint8_t>::value, int> = 0>
192
+ XSIMD_INLINE uint64x2_t x_vreinterpretq(uint8x16_t a) noexcept { return vreinterpretq_u64_u8(a); }
193
+ template <class R, class T, std::enable_if_t<std::is_same<R, uint64_t>::value && std::is_same<T, int8_t>::value, int> = 0>
194
+ XSIMD_INLINE uint64x2_t x_vreinterpretq(int8x16_t a) noexcept { return vreinterpretq_u64_s8(a); }
195
+ template <class R, class T, std::enable_if_t<std::is_same<R, uint64_t>::value && std::is_same<T, uint16_t>::value, int> = 0>
196
+ XSIMD_INLINE uint64x2_t x_vreinterpretq(uint16x8_t a) noexcept { return vreinterpretq_u64_u16(a); }
197
+ template <class R, class T, std::enable_if_t<std::is_same<R, uint64_t>::value && std::is_same<T, int16_t>::value, int> = 0>
198
+ XSIMD_INLINE uint64x2_t x_vreinterpretq(int16x8_t a) noexcept { return vreinterpretq_u64_s16(a); }
199
+ template <class R, class T, std::enable_if_t<std::is_same<R, uint64_t>::value && std::is_same<T, uint32_t>::value, int> = 0>
200
+ XSIMD_INLINE uint64x2_t x_vreinterpretq(uint32x4_t a) noexcept { return vreinterpretq_u64_u32(a); }
201
+ template <class R, class T, std::enable_if_t<std::is_same<R, uint64_t>::value && std::is_same<T, int32_t>::value, int> = 0>
202
+ XSIMD_INLINE uint64x2_t x_vreinterpretq(int32x4_t a) noexcept { return vreinterpretq_u64_s32(a); }
203
+ template <class R, class T, std::enable_if_t<std::is_same<R, uint64_t>::value && std::is_same<T, uint64_t>::value, int> = 0>
204
+ XSIMD_INLINE uint64x2_t x_vreinterpretq(uint64x2_t a) noexcept { return a; }
205
+ template <class R, class T, std::enable_if_t<std::is_same<R, uint64_t>::value && std::is_same<T, int64_t>::value, int> = 0>
206
+ XSIMD_INLINE uint64x2_t x_vreinterpretq(int64x2_t a) noexcept { return vreinterpretq_u64_s64(a); }
207
+ template <class R, class T, std::enable_if_t<std::is_same<R, uint64_t>::value && std::is_same<T, float>::value, int> = 0>
208
+ XSIMD_INLINE uint64x2_t x_vreinterpretq(float32x4_t a) noexcept { return vreinterpretq_u64_f32(a); }
209
+
210
+ // TODO(c++17): Make a single function with if constexpr switch
211
+ // Templating on the scalar type `T` is required because in some compilers (e.g. MSVC)
212
+ // the vector types are all aliases of the same type.
213
+ template <class R, class T, std::enable_if_t<std::is_same<R, int64_t>::value && std::is_same<T, uint8_t>::value, int> = 0>
214
+ XSIMD_INLINE int64x2_t x_vreinterpretq(uint8x16_t a) noexcept { return vreinterpretq_s64_u8(a); }
215
+ template <class R, class T, std::enable_if_t<std::is_same<R, int64_t>::value && std::is_same<T, int8_t>::value, int> = 0>
216
+ XSIMD_INLINE int64x2_t x_vreinterpretq(int8x16_t a) noexcept { return vreinterpretq_s64_s8(a); }
217
+ template <class R, class T, std::enable_if_t<std::is_same<R, int64_t>::value && std::is_same<T, uint16_t>::value, int> = 0>
218
+ XSIMD_INLINE int64x2_t x_vreinterpretq(uint16x8_t a) noexcept { return vreinterpretq_s64_u16(a); }
219
+ template <class R, class T, std::enable_if_t<std::is_same<R, int64_t>::value && std::is_same<T, int16_t>::value, int> = 0>
220
+ XSIMD_INLINE int64x2_t x_vreinterpretq(int16x8_t a) noexcept { return vreinterpretq_s64_s16(a); }
221
+ template <class R, class T, std::enable_if_t<std::is_same<R, int64_t>::value && std::is_same<T, uint32_t>::value, int> = 0>
222
+ XSIMD_INLINE int64x2_t x_vreinterpretq(uint32x4_t a) noexcept { return vreinterpretq_s64_u32(a); }
223
+ template <class R, class T, std::enable_if_t<std::is_same<R, int64_t>::value && std::is_same<T, int32_t>::value, int> = 0>
224
+ XSIMD_INLINE int64x2_t x_vreinterpretq(int32x4_t a) noexcept { return vreinterpretq_s64_s32(a); }
225
+ template <class R, class T, std::enable_if_t<std::is_same<R, int64_t>::value && std::is_same<T, uint64_t>::value, int> = 0>
226
+ XSIMD_INLINE int64x2_t x_vreinterpretq(uint64x2_t a) noexcept { return vreinterpretq_s64_u64(a); }
227
+ template <class R, class T, std::enable_if_t<std::is_same<R, int64_t>::value && std::is_same<T, int64_t>::value, int> = 0>
228
+ XSIMD_INLINE int64x2_t x_vreinterpretq(int64x2_t a) noexcept { return a; }
229
+ template <class R, class T, std::enable_if_t<std::is_same<R, int64_t>::value && std::is_same<T, float>::value, int> = 0>
230
+ XSIMD_INLINE int64x2_t x_vreinterpretq(float32x4_t a) noexcept { return vreinterpretq_s64_f32(a); }
231
+
232
+ // TODO(c++17): Make a single function with if constexpr switch
233
+ // Templating on the scalar type `T` is required because in some compilers (e.g. MSVC)
234
+ // the vector types are all aliases of the same type.
235
+ template <class R, class T, std::enable_if_t<std::is_same<R, float>::value && std::is_same<T, uint8_t>::value, int> = 0>
236
+ XSIMD_INLINE float32x4_t x_vreinterpretq(uint8x16_t a) noexcept { return vreinterpretq_f32_u8(a); }
237
+ template <class R, class T, std::enable_if_t<std::is_same<R, float>::value && std::is_same<T, int8_t>::value, int> = 0>
238
+ XSIMD_INLINE float32x4_t x_vreinterpretq(int8x16_t a) noexcept { return vreinterpretq_f32_s8(a); }
239
+ template <class R, class T, std::enable_if_t<std::is_same<R, float>::value && std::is_same<T, uint16_t>::value, int> = 0>
240
+ XSIMD_INLINE float32x4_t x_vreinterpretq(uint16x8_t a) noexcept { return vreinterpretq_f32_u16(a); }
241
+ template <class R, class T, std::enable_if_t<std::is_same<R, float>::value && std::is_same<T, int16_t>::value, int> = 0>
242
+ XSIMD_INLINE float32x4_t x_vreinterpretq(int16x8_t a) noexcept { return vreinterpretq_f32_s16(a); }
243
+ template <class R, class T, std::enable_if_t<std::is_same<R, float>::value && std::is_same<T, uint32_t>::value, int> = 0>
244
+ XSIMD_INLINE float32x4_t x_vreinterpretq(uint32x4_t a) noexcept { return vreinterpretq_f32_u32(a); }
245
+ template <class R, class T, std::enable_if_t<std::is_same<R, float>::value && std::is_same<T, int32_t>::value, int> = 0>
246
+ XSIMD_INLINE float32x4_t x_vreinterpretq(int32x4_t a) noexcept { return vreinterpretq_f32_s32(a); }
247
+ template <class R, class T, std::enable_if_t<std::is_same<R, float>::value && std::is_same<T, uint64_t>::value, int> = 0>
248
+ XSIMD_INLINE float32x4_t x_vreinterpretq(uint64x2_t a) noexcept { return vreinterpretq_f32_u64(a); }
249
+ template <class R, class T, std::enable_if_t<std::is_same<R, float>::value && std::is_same<T, int64_t>::value, int> = 0>
250
+ XSIMD_INLINE float32x4_t x_vreinterpretq(int64x2_t a) noexcept { return vreinterpretq_f32_s64(a); }
251
+ template <class R, class T, std::enable_if_t<std::is_same<R, float>::value && std::is_same<T, float>::value, int> = 0>
252
+ XSIMD_INLINE float32x4_t x_vreinterpretq(float32x4_t a) noexcept { return a; }
253
+ }
254
+
255
+ template <class A, class T, class R>
256
+ XSIMD_INLINE batch<R, A> bitwise_cast(batch<T, A> const& arg, batch<R, A> const&, requires_arch<neon>) noexcept
257
+ {
258
+ using src_register_type = typename batch<T, A>::register_type;
259
+ return wrap::x_vreinterpretq<map_to_sized_type_t<R>, map_to_sized_type_t<T>>(src_register_type(arg));
260
+ }
261
+
262
+ /*************
263
+ * broadcast *
264
+ *************/
265
+
266
+ template <class A, class T, detail::enable_sized_unsigned_t<T, 1> = 0>
267
+ XSIMD_INLINE batch<T, A> broadcast(T val, requires_arch<neon>) noexcept
268
+ {
269
+ return vdupq_n_u8(uint8_t(val));
270
+ }
271
+
272
+ template <class A, class T, detail::enable_sized_signed_t<T, 1> = 0>
273
+ XSIMD_INLINE batch<T, A> broadcast(T val, requires_arch<neon>) noexcept
274
+ {
275
+ return vdupq_n_s8(int8_t(val));
276
+ }
277
+
278
+ template <class A, class T, detail::enable_sized_unsigned_t<T, 2> = 0>
279
+ XSIMD_INLINE batch<T, A> broadcast(T val, requires_arch<neon>) noexcept
280
+ {
281
+ return vdupq_n_u16(uint16_t(val));
282
+ }
283
+
284
+ template <class A, class T, detail::enable_sized_signed_t<T, 2> = 0>
285
+ XSIMD_INLINE batch<T, A> broadcast(T val, requires_arch<neon>) noexcept
286
+ {
287
+ return vdupq_n_s16(int16_t(val));
288
+ }
289
+
290
+ template <class A, class T, detail::enable_sized_unsigned_t<T, 4> = 0>
291
+ XSIMD_INLINE batch<T, A> broadcast(T val, requires_arch<neon>) noexcept
292
+ {
293
+ return vdupq_n_u32(uint32_t(val));
294
+ }
295
+
296
+ template <class A, class T, detail::enable_sized_signed_t<T, 4> = 0>
297
+ XSIMD_INLINE batch<T, A> broadcast(T val, requires_arch<neon>) noexcept
298
+ {
299
+ return vdupq_n_s32(int32_t(val));
300
+ }
301
+
302
+ template <class A, class T, detail::enable_sized_unsigned_t<T, 8> = 0>
303
+ XSIMD_INLINE batch<T, A> broadcast(T val, requires_arch<neon>) noexcept
304
+ {
305
+ return vdupq_n_u64(uint64_t(val));
306
+ }
307
+
308
+ template <class A, class T, detail::enable_sized_signed_t<T, 8> = 0>
309
+ XSIMD_INLINE batch<T, A> broadcast(T val, requires_arch<neon>) noexcept
310
+ {
311
+ return vdupq_n_s64(int64_t(val));
312
+ }
313
+
314
+ template <class A>
315
+ XSIMD_INLINE batch<float, A> broadcast(float val, requires_arch<neon>) noexcept
316
+ {
317
+ return vdupq_n_f32(val);
318
+ }
319
+
320
+ /*************
321
+ * from_bool *
322
+ *************/
323
+
324
+ template <class A, class T, detail::enable_sized_unsigned_t<T, 1> = 0>
325
+ XSIMD_INLINE batch<T, A> from_bool(batch_bool<T, A> const& arg, requires_arch<neon>) noexcept
326
+ {
327
+ return vandq_u8(arg, vdupq_n_u8(1));
328
+ }
329
+
330
+ template <class A, class T, detail::enable_sized_signed_t<T, 1> = 0>
331
+ XSIMD_INLINE batch<T, A> from_bool(batch_bool<T, A> const& arg, requires_arch<neon>) noexcept
332
+ {
333
+ return vreinterpretq_s8_u8(vandq_u8(arg.data, vdupq_n_u8(1)));
334
+ }
335
+
336
+ template <class A, class T, detail::enable_sized_unsigned_t<T, 2> = 0>
337
+ XSIMD_INLINE batch<T, A> from_bool(batch_bool<T, A> const& arg, requires_arch<neon>) noexcept
338
+ {
339
+ return vandq_u16(arg, vdupq_n_u16(1));
340
+ }
341
+
342
+ template <class A, class T, detail::enable_sized_signed_t<T, 2> = 0>
343
+ XSIMD_INLINE batch<T, A> from_bool(batch_bool<T, A> const& arg, requires_arch<neon>) noexcept
344
+ {
345
+ return vreinterpretq_s16_u16(vandq_u16(arg.data, vdupq_n_u16(1)));
346
+ }
347
+
348
+ template <class A, class T, detail::enable_sized_unsigned_t<T, 4> = 0>
349
+ XSIMD_INLINE batch<T, A> from_bool(batch_bool<T, A> const& arg, requires_arch<neon>) noexcept
350
+ {
351
+ return vandq_u32(arg, vdupq_n_u32(1));
352
+ }
353
+
354
+ template <class A, class T, detail::enable_sized_signed_t<T, 4> = 0>
355
+ XSIMD_INLINE batch<T, A> from_bool(batch_bool<T, A> const& arg, requires_arch<neon>) noexcept
356
+ {
357
+ return vreinterpretq_s32_u32(vandq_u32(arg.data, vdupq_n_u32(1)));
358
+ }
359
+
360
+ template <class A, class T, detail::enable_sized_unsigned_t<T, 8> = 0>
361
+ XSIMD_INLINE batch<T, A> from_bool(batch_bool<T, A> const& arg, requires_arch<neon>) noexcept
362
+ {
363
+ return vandq_u64(arg, vdupq_n_u64(1));
364
+ }
365
+
366
+ template <class A, class T, detail::enable_sized_signed_t<T, 8> = 0>
367
+ XSIMD_INLINE batch<T, A> from_bool(batch_bool<T, A> const& arg, requires_arch<neon>) noexcept
368
+ {
369
+ return vreinterpretq_s64_u64(vandq_u64(arg.data, vdupq_n_u64(1)));
370
+ }
371
+
372
+ template <class A>
373
+ XSIMD_INLINE batch<float, A> from_bool(batch_bool<float, A> const& arg, requires_arch<neon>) noexcept
374
+ {
375
+ return vreinterpretq_f32_u32(vandq_u32(arg, vreinterpretq_u32_f32(vdupq_n_f32(1.f))));
376
+ }
377
+
378
+ /********
379
+ * load *
380
+ ********/
381
+
382
+ // It is not possible to use a call to A::alignment() here, so use an
383
+ // immediate instead.
384
+ #if defined(__clang__) || defined(__GNUC__)
385
+ #define xsimd_aligned_load(inst, type, expr) inst((type)__builtin_assume_aligned(expr, 16))
386
+ #else
387
+ #define xsimd_aligned_load(inst, type, expr) inst((type)expr)
388
+ #endif
389
+
390
+ template <class A, class T, detail::enable_sized_unsigned_t<T, 1> = 0>
391
+ XSIMD_INLINE batch<T, A> load_aligned(T const* src, convert<T>, requires_arch<neon>) noexcept
392
+ {
393
+ return xsimd_aligned_load(vld1q_u8, uint8_t*, src);
394
+ }
395
+
396
+ template <class A, class T, detail::enable_sized_signed_t<T, 1> = 0>
397
+ XSIMD_INLINE batch<T, A> load_aligned(T const* src, convert<T>, requires_arch<neon>) noexcept
398
+ {
399
+ return xsimd_aligned_load(vld1q_s8, int8_t*, src);
400
+ }
401
+
402
+ template <class A, class T, detail::enable_sized_unsigned_t<T, 2> = 0>
403
+ XSIMD_INLINE batch<T, A> load_aligned(T const* src, convert<T>, requires_arch<neon>) noexcept
404
+ {
405
+ return xsimd_aligned_load(vld1q_u16, uint16_t*, src);
406
+ }
407
+ template <class A, class T, detail::enable_sized_signed_t<T, 2> = 0>
408
+ XSIMD_INLINE batch<T, A> load_aligned(T const* src, convert<T>, requires_arch<neon>) noexcept
409
+ {
410
+ return xsimd_aligned_load(vld1q_s16, int16_t*, src);
411
+ }
412
+ template <class A, class T, detail::enable_sized_unsigned_t<T, 4> = 0>
413
+ XSIMD_INLINE batch<T, A> load_aligned(T const* src, convert<T>, requires_arch<neon>) noexcept
414
+ {
415
+ return xsimd_aligned_load(vld1q_u32, uint32_t*, src);
416
+ }
417
+ template <class A, class T, detail::enable_sized_signed_t<T, 4> = 0>
418
+ XSIMD_INLINE batch<T, A> load_aligned(T const* src, convert<T>, requires_arch<neon>) noexcept
419
+ {
420
+ return xsimd_aligned_load(vld1q_s32, int32_t*, src);
421
+ }
422
+ template <class A, class T, detail::enable_sized_unsigned_t<T, 8> = 0>
423
+ XSIMD_INLINE batch<T, A> load_aligned(T const* src, convert<T>, requires_arch<neon>) noexcept
424
+ {
425
+ return xsimd_aligned_load(vld1q_u64, uint64_t*, src);
426
+ }
427
+ template <class A, class T, detail::enable_sized_signed_t<T, 8> = 0>
428
+ XSIMD_INLINE batch<T, A> load_aligned(T const* src, convert<T>, requires_arch<neon>) noexcept
429
+ {
430
+ return xsimd_aligned_load(vld1q_s64, int64_t*, src);
431
+ }
432
+
433
+ template <class A>
434
+ XSIMD_INLINE batch<float, A> load_aligned(float const* src, convert<float>, requires_arch<neon>) noexcept
435
+ {
436
+ return xsimd_aligned_load(vld1q_f32, float*, src);
437
+ }
438
+
439
+ #undef xsimd_aligned_load
440
+
441
+ template <class A, class T, detail::enable_sized_unsigned_t<T, 1> = 0>
442
+ XSIMD_INLINE batch<T, A> load_unaligned(T const* src, convert<T>, requires_arch<neon>) noexcept
443
+ {
444
+ return vld1q_u8((uint8_t*)src);
445
+ }
446
+
447
+ template <class A, class T, detail::enable_sized_signed_t<T, 1> = 0>
448
+ XSIMD_INLINE batch<T, A> load_unaligned(T const* src, convert<T>, requires_arch<neon>) noexcept
449
+ {
450
+ return vld1q_s8((int8_t*)src);
451
+ }
452
+
453
+ template <class A, class T, detail::enable_sized_unsigned_t<T, 2> = 0>
454
+ XSIMD_INLINE batch<T, A> load_unaligned(T const* src, convert<T>, requires_arch<neon>) noexcept
455
+ {
456
+ return vld1q_u16((uint16_t*)src);
457
+ }
458
+ template <class A, class T, detail::enable_sized_signed_t<T, 2> = 0>
459
+ XSIMD_INLINE batch<T, A> load_unaligned(T const* src, convert<T>, requires_arch<neon>) noexcept
460
+ {
461
+ return vld1q_s16((int16_t*)src);
462
+ }
463
+ template <class A, class T, detail::enable_sized_unsigned_t<T, 4> = 0>
464
+ XSIMD_INLINE batch<T, A> load_unaligned(T const* src, convert<T>, requires_arch<neon>) noexcept
465
+ {
466
+ return vld1q_u32((uint32_t*)src);
467
+ }
468
+ template <class A, class T, detail::enable_sized_signed_t<T, 4> = 0>
469
+ XSIMD_INLINE batch<T, A> load_unaligned(T const* src, convert<T>, requires_arch<neon>) noexcept
470
+ {
471
+ return vld1q_s32((int32_t*)src);
472
+ }
473
+ template <class A, class T, detail::enable_sized_unsigned_t<T, 8> = 0>
474
+ XSIMD_INLINE batch<T, A> load_unaligned(T const* src, convert<T>, requires_arch<neon>) noexcept
475
+ {
476
+ return vld1q_u64((uint64_t*)src);
477
+ }
478
+ template <class A, class T, detail::enable_sized_signed_t<T, 8> = 0>
479
+ XSIMD_INLINE batch<T, A> load_unaligned(T const* src, convert<T>, requires_arch<neon>) noexcept
480
+ {
481
+ return vld1q_s64((int64_t*)src);
482
+ }
483
+
484
+ template <class A>
485
+ XSIMD_INLINE batch<float, A> load_unaligned(float const* src, convert<float>, requires_arch<neon>) noexcept
486
+ {
487
+ return vld1q_f32(src);
488
+ }
489
+
490
+ /* batch bool version */
491
+ template <class A, class T, detail::enable_sized_t<T, 1> = 0>
492
+ XSIMD_INLINE batch_bool<T, A> load_unaligned(bool const* mem, batch_bool<T, A>, requires_arch<neon>) noexcept
493
+ {
494
+ auto vmem = load_unaligned<A>((unsigned char const*)mem, convert<unsigned char> {}, A {});
495
+ auto const zero = batch<unsigned char, A> { 0 };
496
+ return { (zero - vmem).data };
497
+ }
498
+ template <class A, class T, detail::enable_sized_t<T, 1> = 0>
499
+ XSIMD_INLINE batch_bool<T, A> load_aligned(bool const* mem, batch_bool<T, A> t, requires_arch<neon> r) noexcept
500
+ {
501
+ return load_unaligned(mem, t, r);
502
+ }
503
+
504
+ template <class A, class T, detail::enable_sized_t<T, 2> = 0>
505
+ XSIMD_INLINE batch_bool<T, A> load_unaligned(bool const* mem, batch_bool<T, A>, requires_arch<neon>) noexcept
506
+ {
507
+ auto const vmem = batch<uint16_t, A>(vmovl_u8(vld1_u8((unsigned char const*)mem)));
508
+ auto const zero = batch<uint16_t, A> { 0 };
509
+ return { (zero - vmem).data };
510
+ }
511
+
512
+ template <class A, class T, detail::enable_sized_t<T, 2> = 0>
513
+ XSIMD_INLINE batch_bool<T, A> load_aligned(bool const* mem, batch_bool<T, A> t, requires_arch<neon> r) noexcept
514
+ {
515
+ return load_unaligned(mem, t, r);
516
+ }
517
+
518
+ template <class A, class T, detail::enable_sized_t<T, 4> = 0>
519
+ XSIMD_INLINE batch_bool<T, A> load_unaligned(bool const* mem, batch_bool<T, A>, requires_arch<neon>) noexcept
520
+ {
521
+ uint8x8_t tmp = vreinterpret_u8_u32(vset_lane_u32(*(unsigned int*)mem, vdup_n_u32(0), 0));
522
+ auto const vmem = batch<uint32_t, A>(vmovl_u16(vget_low_u16(vmovl_u8(tmp))));
523
+ auto const zero = batch<uint32_t, A> { 0 };
524
+ return { (zero - vmem).data };
525
+ }
526
+
527
+ template <class A, class T, detail::enable_sized_t<T, 4> = 0>
528
+ XSIMD_INLINE batch_bool<T, A> load_aligned(bool const* mem, batch_bool<T, A> t, requires_arch<neon> r) noexcept
529
+ {
530
+ return load_unaligned(mem, t, r);
531
+ }
532
+
533
+ /* masked version */
534
+ namespace detail
535
+ {
536
+ template <bool... Values>
537
+ struct load_masked;
538
+
539
+ template <>
540
+ struct load_masked<>
541
+ {
542
+ template <size_t I, class A, class T, bool Use>
543
+ static XSIMD_INLINE batch<T, A> apply(T const* /* mem */, batch<T, A> acc, std::integral_constant<bool, Use>) noexcept
544
+ {
545
+ return acc;
546
+ }
547
+ };
548
+ template <bool Value, bool... Values>
549
+ struct load_masked<Value, Values...>
550
+ {
551
+ template <size_t I, class A, class T>
552
+ static XSIMD_INLINE batch<T, A> apply(T const* mem, batch<T, A> acc, std::true_type) noexcept
553
+ {
554
+ return load_masked<Values...>::template apply<I + 1>(mem, insert(acc, mem[I], index<I> {}), std::integral_constant<bool, Value> {});
555
+ }
556
+ template <size_t I, class A, class T>
557
+ static XSIMD_INLINE batch<T, A> apply(T const* mem, batch<T, A> acc, std::false_type) noexcept
558
+ {
559
+ return load_masked<Values...>::template apply<I + 1>(mem, acc, std::integral_constant<bool, Value> {});
560
+ }
561
+ };
562
+ }
563
+
564
+ template <class A, class T, bool Value, bool... Values, class Mode>
565
+ XSIMD_INLINE batch<T, A> load_masked(T const* mem, batch_bool_constant<T, A, Value, Values...> /* mask */, Mode, requires_arch<neon>) noexcept
566
+ {
567
+ // Call insert whenever Values... are true
568
+ return detail::load_masked<Values...>::template apply<0>(mem, broadcast(T(0), A {}), std::integral_constant<bool, Value> {});
569
+ }
570
+
571
+ /*********
572
+ * store *
573
+ *********/
574
+
575
+ template <class A, class T, detail::enable_sized_unsigned_t<T, 1> = 0>
576
+ XSIMD_INLINE void store_aligned(T* dst, batch<T, A> const& src, requires_arch<neon>) noexcept
577
+ {
578
+ vst1q_u8((uint8_t*)dst, src);
579
+ }
580
+
581
+ template <class A, class T, detail::enable_sized_signed_t<T, 1> = 0>
582
+ XSIMD_INLINE void store_aligned(T* dst, batch<T, A> const& src, requires_arch<neon>) noexcept
583
+ {
584
+ vst1q_s8((int8_t*)dst, src);
585
+ }
586
+
587
+ template <class A, class T, detail::enable_sized_unsigned_t<T, 2> = 0>
588
+ XSIMD_INLINE void store_aligned(T* dst, batch<T, A> const& src, requires_arch<neon>) noexcept
589
+ {
590
+ vst1q_u16((uint16_t*)dst, src);
591
+ }
592
+
593
+ template <class A, class T, detail::enable_sized_signed_t<T, 2> = 0>
594
+ XSIMD_INLINE void store_aligned(T* dst, batch<T, A> const& src, requires_arch<neon>) noexcept
595
+ {
596
+ vst1q_s16((int16_t*)dst, src);
597
+ }
598
+
599
+ template <class A, class T, detail::enable_sized_unsigned_t<T, 4> = 0>
600
+ XSIMD_INLINE void store_aligned(T* dst, batch<T, A> const& src, requires_arch<neon>) noexcept
601
+ {
602
+ vst1q_u32((uint32_t*)dst, src);
603
+ }
604
+
605
+ template <class A, class T, detail::enable_sized_signed_t<T, 4> = 0>
606
+ XSIMD_INLINE void store_aligned(T* dst, batch<T, A> const& src, requires_arch<neon>) noexcept
607
+ {
608
+ vst1q_s32((int32_t*)dst, src);
609
+ }
610
+
611
+ template <class A, class T, detail::enable_sized_unsigned_t<T, 8> = 0>
612
+ XSIMD_INLINE void store_aligned(T* dst, batch<T, A> const& src, requires_arch<neon>) noexcept
613
+ {
614
+ vst1q_u64((uint64_t*)dst, src);
615
+ }
616
+
617
+ template <class A, class T, detail::enable_sized_signed_t<T, 8> = 0>
618
+ XSIMD_INLINE void store_aligned(T* dst, batch<T, A> const& src, requires_arch<neon>) noexcept
619
+ {
620
+ vst1q_s64((int64_t*)dst, src);
621
+ }
622
+
623
+ template <class A>
624
+ XSIMD_INLINE void store_aligned(float* dst, batch<float, A> const& src, requires_arch<neon>) noexcept
625
+ {
626
+ vst1q_f32(dst, src);
627
+ }
628
+
629
+ template <class A, class T>
630
+ XSIMD_INLINE void store_unaligned(T* dst, batch<T, A> const& src, requires_arch<neon>) noexcept
631
+ {
632
+ store_aligned<A>(dst, src, A {});
633
+ }
634
+
635
+ /****************
636
+ * load_complex *
637
+ ****************/
638
+
639
+ template <class A>
640
+ XSIMD_INLINE batch<std::complex<float>, A> load_complex_aligned(std::complex<float> const* mem, convert<std::complex<float>>, requires_arch<neon>) noexcept
641
+ {
642
+ using real_batch = batch<float, A>;
643
+ const float* buf = reinterpret_cast<const float*>(mem);
644
+ float32x4x2_t tmp = vld2q_f32(buf);
645
+ real_batch real = tmp.val[0],
646
+ imag = tmp.val[1];
647
+ return batch<std::complex<float>, A> { real, imag };
648
+ }
649
+
650
+ template <class A>
651
+ XSIMD_INLINE batch<std::complex<float>, A> load_complex_unaligned(std::complex<float> const* mem, convert<std::complex<float>> cvt, requires_arch<neon>) noexcept
652
+ {
653
+ return load_complex_aligned<A>(mem, cvt, A {});
654
+ }
655
+
656
+ /*****************
657
+ * store_complex *
658
+ *****************/
659
+
660
+ template <class A>
661
+ XSIMD_INLINE void store_complex_aligned(std::complex<float>* dst, batch<std::complex<float>, A> const& src, requires_arch<neon>) noexcept
662
+ {
663
+ float32x4x2_t tmp;
664
+ tmp.val[0] = src.real();
665
+ tmp.val[1] = src.imag();
666
+ float* buf = reinterpret_cast<float*>(dst);
667
+ vst2q_f32(buf, tmp);
668
+ }
669
+
670
+ template <class A>
671
+ XSIMD_INLINE void store_complex_unaligned(std::complex<float>* dst, batch<std::complex<float>, A> const& src, requires_arch<neon>) noexcept
672
+ {
673
+ store_complex_aligned(dst, src, A {});
674
+ }
675
+
676
+ /*********************
677
+ * store<batch_bool> *
678
+ *********************/
679
+ template <class T, class A, detail::enable_sized_t<T, 1> = 0>
680
+ XSIMD_INLINE void store(batch_bool<T, A> b, bool* mem, requires_arch<neon>) noexcept
681
+ {
682
+ uint8x16_t val = vshrq_n_u8(b.data, 7);
683
+ alignas(A::alignment()) uint8_t buffer[batch_bool<T, A>::size];
684
+ vst1q_u8(buffer, val);
685
+ memcpy(mem, buffer, sizeof(buffer));
686
+ }
687
+
688
+ template <class T, class A, detail::enable_sized_t<T, 2> = 0>
689
+ XSIMD_INLINE void store(batch_bool<T, A> b, bool* mem, requires_arch<neon>) noexcept
690
+ {
691
+ uint8x8_t val = vshr_n_u8(vqmovn_u16(b.data), 7);
692
+ alignas(A::alignment()) uint8_t buffer[batch_bool<T, A>::size];
693
+ vst1_u8(buffer, val);
694
+ memcpy(mem, buffer, sizeof(buffer));
695
+ }
696
+
697
+ template <class T, class A, detail::enable_sized_t<T, 4> = 0>
698
+ XSIMD_INLINE void store(batch_bool<T, A> b, bool* mem, requires_arch<neon>) noexcept
699
+ {
700
+ uint8x8_t val = vshr_n_u8(vqmovn_u16(vcombine_u16(vqmovn_u32(b.data), vdup_n_u16(0))), 7);
701
+ alignas(A::alignment()) uint8_t buffer[8];
702
+ vst1_u8(buffer, val);
703
+ memcpy(mem, buffer, batch_bool<T, A>::size);
704
+ }
705
+
706
+ template <class T, class A, detail::enable_sized_t<T, 8> = 0>
707
+ XSIMD_INLINE void store(batch_bool<T, A> b, bool* mem, requires_arch<neon>) noexcept
708
+ {
709
+ uint8x8_t val = vshr_n_u8(vqmovn_u16(vcombine_u16(vqmovn_u32(vcombine_u32(vqmovn_u64(b.data), vdup_n_u32(0))), vdup_n_u16(0))), 7);
710
+ alignas(A::alignment()) uint8_t buffer[8];
711
+ vst1_u8(buffer, val);
712
+ memcpy(mem, buffer, batch_bool<T, A>::size);
713
+ }
714
+
715
+ template <class A>
716
+ XSIMD_INLINE void store(batch_bool<float, A> b, bool* mem, requires_arch<neon>) noexcept
717
+ {
718
+ store(batch_bool<uint32_t, A>(b.data), mem, A {});
719
+ }
720
+
721
+ /*******
722
+ * set *
723
+ *******/
724
+
725
+ template <class A, class T, class... Args, detail::enable_integral_t<T> = 0>
726
+ XSIMD_INLINE batch<T, A> set(batch<T, A> const&, requires_arch<neon> req, Args... args) noexcept
727
+ {
728
+ alignas(A::alignment()) T data[] = { static_cast<T>(args)... };
729
+ return load_aligned<A, T>(data, {}, req);
730
+ }
731
+
732
+ template <class A, class T, class... Args, detail::enable_integral_t<T> = 0>
733
+ XSIMD_INLINE batch_bool<T, A> set(batch_bool<T, A> const&, requires_arch<neon>, Args... args) noexcept
734
+ {
735
+ using unsigned_type = as_unsigned_integer_t<T>;
736
+ auto const out = batch<unsigned_type, A> { static_cast<unsigned_type>(args ? -1LL : 0LL)... };
737
+ return { out.data };
738
+ }
739
+
740
+ template <class A>
741
+ XSIMD_INLINE batch<float, A> set(batch<float, A> const&, requires_arch<neon> req, float f0, float f1, float f2, float f3) noexcept
742
+ {
743
+ alignas(A::alignment()) float data[] = { f0, f1, f2, f3 };
744
+ return load_aligned<A>(data, {}, req);
745
+ }
746
+
747
+ template <class A>
748
+ XSIMD_INLINE batch<std::complex<float>, A> set(batch<std::complex<float>, A> const&, requires_arch<neon>,
749
+ std::complex<float> c0, std::complex<float> c1,
750
+ std::complex<float> c2, std::complex<float> c3) noexcept
751
+ {
752
+ return batch<std::complex<float>, A>(float32x4_t { c0.real(), c1.real(), c2.real(), c3.real() },
753
+ float32x4_t { c0.imag(), c1.imag(), c2.imag(), c3.imag() });
754
+ }
755
+
756
+ template <class A, class... Args>
757
+ XSIMD_INLINE batch_bool<float, A> set(batch_bool<float, A> const&, requires_arch<neon>, Args... args) noexcept
758
+ {
759
+ using unsigned_type = as_unsigned_integer_t<float>;
760
+ auto const out = batch<unsigned_type, A> { static_cast<unsigned_type>(args ? -1LL : 0LL)... };
761
+ return { out.data };
762
+ }
763
+
764
+ /*******
765
+ * neg *
766
+ *******/
767
+
768
+ template <class A, class T, detail::enable_sized_unsigned_t<T, 1> = 0>
769
+ XSIMD_INLINE batch<T, A> neg(batch<T, A> const& rhs, requires_arch<neon>) noexcept
770
+ {
771
+ return vreinterpretq_u8_s8(vnegq_s8(vreinterpretq_s8_u8(rhs)));
772
+ }
773
+
774
+ template <class A, class T, detail::enable_sized_signed_t<T, 1> = 0>
775
+ XSIMD_INLINE batch<T, A> neg(batch<T, A> const& rhs, requires_arch<neon>) noexcept
776
+ {
777
+ return vnegq_s8(rhs);
778
+ }
779
+
780
+ template <class A, class T, detail::enable_sized_unsigned_t<T, 2> = 0>
781
+ XSIMD_INLINE batch<T, A> neg(batch<T, A> const& rhs, requires_arch<neon>) noexcept
782
+ {
783
+ return vreinterpretq_u16_s16(vnegq_s16(vreinterpretq_s16_u16(rhs)));
784
+ }
785
+
786
+ template <class A, class T, detail::enable_sized_signed_t<T, 2> = 0>
787
+ XSIMD_INLINE batch<T, A> neg(batch<T, A> const& rhs, requires_arch<neon>) noexcept
788
+ {
789
+ return vnegq_s16(rhs);
790
+ }
791
+
792
+ template <class A, class T, detail::enable_sized_unsigned_t<T, 4> = 0>
793
+ XSIMD_INLINE batch<T, A> neg(batch<T, A> const& rhs, requires_arch<neon>) noexcept
794
+ {
795
+ return vreinterpretq_u32_s32(vnegq_s32(vreinterpretq_s32_u32(rhs)));
796
+ }
797
+
798
+ template <class A, class T, detail::enable_sized_signed_t<T, 4> = 0>
799
+ XSIMD_INLINE batch<T, A> neg(batch<T, A> const& rhs, requires_arch<neon>) noexcept
800
+ {
801
+ return vnegq_s32(rhs);
802
+ }
803
+
804
+ template <class A, class T, detail::enable_sized_integral_t<T, 8> = 0>
805
+ XSIMD_INLINE batch<T, A> neg(batch<T, A> const& rhs, requires_arch<neon>) noexcept
806
+ {
807
+ return 0 - rhs;
808
+ }
809
+
810
+ template <class A>
811
+ XSIMD_INLINE batch<float, A> neg(batch<float, A> const& rhs, requires_arch<neon>) noexcept
812
+ {
813
+ return vnegq_f32(rhs);
814
+ }
815
+
816
+ /*******
817
+ * add *
818
+ *******/
819
+
820
+ namespace wrap
821
+ {
822
+ // TODO(c++17): Make a single function with if constexpr switch
823
+ // Templating on the scalar type `T` is required because in some compilers (e.g. MSVC)
824
+ // the vector types are all aliases of the same type.
825
+ template <class T, std::enable_if_t<std::is_same<T, uint8_t>::value, int> = 0>
826
+ XSIMD_INLINE uint8x16_t x_vaddq(uint8x16_t a, uint8x16_t b) noexcept { return vaddq_u8(a, b); }
827
+ template <class T, std::enable_if_t<std::is_same<T, int8_t>::value, int> = 0>
828
+ XSIMD_INLINE int8x16_t x_vaddq(int8x16_t a, int8x16_t b) noexcept { return vaddq_s8(a, b); }
829
+ template <class T, std::enable_if_t<std::is_same<T, uint16_t>::value, int> = 0>
830
+ XSIMD_INLINE uint16x8_t x_vaddq(uint16x8_t a, uint16x8_t b) noexcept { return vaddq_u16(a, b); }
831
+ template <class T, std::enable_if_t<std::is_same<T, int16_t>::value, int> = 0>
832
+ XSIMD_INLINE int16x8_t x_vaddq(int16x8_t a, int16x8_t b) noexcept { return vaddq_s16(a, b); }
833
+ template <class T, std::enable_if_t<std::is_same<T, uint32_t>::value, int> = 0>
834
+ XSIMD_INLINE uint32x4_t x_vaddq(uint32x4_t a, uint32x4_t b) noexcept { return vaddq_u32(a, b); }
835
+ template <class T, std::enable_if_t<std::is_same<T, int32_t>::value, int> = 0>
836
+ XSIMD_INLINE int32x4_t x_vaddq(int32x4_t a, int32x4_t b) noexcept { return vaddq_s32(a, b); }
837
+ template <class T, std::enable_if_t<std::is_same<T, uint64_t>::value, int> = 0>
838
+ XSIMD_INLINE uint64x2_t x_vaddq(uint64x2_t a, uint64x2_t b) noexcept { return vaddq_u64(a, b); }
839
+ template <class T, std::enable_if_t<std::is_same<T, int64_t>::value, int> = 0>
840
+ XSIMD_INLINE int64x2_t x_vaddq(int64x2_t a, int64x2_t b) noexcept { return vaddq_s64(a, b); }
841
+ template <class T, std::enable_if_t<std::is_same<T, float>::value, int> = 0>
842
+ XSIMD_INLINE float32x4_t x_vaddq(float32x4_t a, float32x4_t b) noexcept { return vaddq_f32(a, b); }
843
+ }
844
+
845
+ template <class A, class T, detail::enable_neon_type_t<T> = 0>
846
+ XSIMD_INLINE batch<T, A> add(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon>) noexcept
847
+ {
848
+ using register_type = typename batch<T, A>::register_type;
849
+ return wrap::x_vaddq<map_to_sized_type_t<T>>(register_type(lhs), register_type(rhs));
850
+ }
851
+
852
+ /*******
853
+ * avg *
854
+ *******/
855
+
856
+ namespace wrap
857
+ {
858
+ // TODO(c++17): Make a single function with if constexpr switch
859
+ // Templating on the scalar type `T` is required because in some compilers (e.g. MSVC)
860
+ // the vector types are all aliases of the same type.
861
+ template <class T, std::enable_if_t<std::is_same<T, uint8_t>::value, int> = 0>
862
+ XSIMD_INLINE uint8x16_t x_vhaddq(uint8x16_t a, uint8x16_t b) noexcept { return vhaddq_u8(a, b); }
863
+ template <class T, std::enable_if_t<std::is_same<T, uint16_t>::value, int> = 0>
864
+ XSIMD_INLINE uint16x8_t x_vhaddq(uint16x8_t a, uint16x8_t b) noexcept { return vhaddq_u16(a, b); }
865
+ template <class T, std::enable_if_t<std::is_same<T, uint32_t>::value, int> = 0>
866
+ XSIMD_INLINE uint32x4_t x_vhaddq(uint32x4_t a, uint32x4_t b) noexcept { return vhaddq_u32(a, b); }
867
+ }
868
+
869
+ template <class A, class T, class = std::enable_if_t<(std::is_unsigned<T>::value && sizeof(T) != 8)>>
870
+ XSIMD_INLINE batch<T, A> avg(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon>) noexcept
871
+ {
872
+ using register_type = typename batch<T, A>::register_type;
873
+ return wrap::x_vhaddq<map_to_sized_type_t<T>>(register_type(lhs), register_type(rhs));
874
+ }
875
+
876
+ /********
877
+ * avgr *
878
+ ********/
879
+
880
+ namespace wrap
881
+ {
882
+ // TODO(c++17): Make a single function with if constexpr switch
883
+ // Templating on the scalar type `T` is required because in some compilers (e.g. MSVC)
884
+ // the vector types are all aliases of the same type.
885
+ template <class T, std::enable_if_t<std::is_same<T, uint8_t>::value, int> = 0>
886
+ XSIMD_INLINE uint8x16_t x_vrhaddq(uint8x16_t a, uint8x16_t b) noexcept { return vrhaddq_u8(a, b); }
887
+ template <class T, std::enable_if_t<std::is_same<T, uint16_t>::value, int> = 0>
888
+ XSIMD_INLINE uint16x8_t x_vrhaddq(uint16x8_t a, uint16x8_t b) noexcept { return vrhaddq_u16(a, b); }
889
+ template <class T, std::enable_if_t<std::is_same<T, uint32_t>::value, int> = 0>
890
+ XSIMD_INLINE uint32x4_t x_vrhaddq(uint32x4_t a, uint32x4_t b) noexcept { return vrhaddq_u32(a, b); }
891
+ }
892
+
893
+ template <class A, class T, class = std::enable_if_t<(std::is_unsigned<T>::value && sizeof(T) != 8)>>
894
+ XSIMD_INLINE batch<T, A> avgr(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon>) noexcept
895
+ {
896
+ using register_type = typename batch<T, A>::register_type;
897
+ return wrap::x_vrhaddq<map_to_sized_type_t<T>>(register_type(lhs), register_type(rhs));
898
+ }
899
+
900
+ /********
901
+ * sadd *
902
+ ********/
903
+
904
+ namespace wrap
905
+ {
906
+ // TODO(c++17): Make a single function with if constexpr switch
907
+ // Templating on the scalar type `T` is required because in some compilers (e.g. MSVC)
908
+ // the vector types are all aliases of the same type.
909
+ template <class T, std::enable_if_t<std::is_same<T, uint8_t>::value, int> = 0>
910
+ XSIMD_INLINE uint8x16_t x_vqaddq(uint8x16_t a, uint8x16_t b) noexcept { return vqaddq_u8(a, b); }
911
+ template <class T, std::enable_if_t<std::is_same<T, int8_t>::value, int> = 0>
912
+ XSIMD_INLINE int8x16_t x_vqaddq(int8x16_t a, int8x16_t b) noexcept { return vqaddq_s8(a, b); }
913
+ template <class T, std::enable_if_t<std::is_same<T, uint16_t>::value, int> = 0>
914
+ XSIMD_INLINE uint16x8_t x_vqaddq(uint16x8_t a, uint16x8_t b) noexcept { return vqaddq_u16(a, b); }
915
+ template <class T, std::enable_if_t<std::is_same<T, int16_t>::value, int> = 0>
916
+ XSIMD_INLINE int16x8_t x_vqaddq(int16x8_t a, int16x8_t b) noexcept { return vqaddq_s16(a, b); }
917
+ template <class T, std::enable_if_t<std::is_same<T, uint32_t>::value, int> = 0>
918
+ XSIMD_INLINE uint32x4_t x_vqaddq(uint32x4_t a, uint32x4_t b) noexcept { return vqaddq_u32(a, b); }
919
+ template <class T, std::enable_if_t<std::is_same<T, int32_t>::value, int> = 0>
920
+ XSIMD_INLINE int32x4_t x_vqaddq(int32x4_t a, int32x4_t b) noexcept { return vqaddq_s32(a, b); }
921
+ template <class T, std::enable_if_t<std::is_same<T, uint64_t>::value, int> = 0>
922
+ XSIMD_INLINE uint64x2_t x_vqaddq(uint64x2_t a, uint64x2_t b) noexcept { return vqaddq_u64(a, b); }
923
+ template <class T, std::enable_if_t<std::is_same<T, int64_t>::value, int> = 0>
924
+ XSIMD_INLINE int64x2_t x_vqaddq(int64x2_t a, int64x2_t b) noexcept { return vqaddq_s64(a, b); }
925
+ template <class T, std::enable_if_t<std::is_same<T, float>::value, int> = 0>
926
+ XSIMD_INLINE float32x4_t x_vqaddq(float32x4_t a, float32x4_t b) noexcept { return vaddq_f32(a, b); }
927
+ }
928
+
929
+ template <class A, class T, detail::enable_neon_type_t<T> = 0>
930
+ XSIMD_INLINE batch<T, A> sadd(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon>) noexcept
931
+ {
932
+ using register_type = typename batch<T, A>::register_type;
933
+ return wrap::x_vqaddq<map_to_sized_type_t<T>>(register_type(lhs), register_type(rhs));
934
+ }
935
+
936
+ /*******
937
+ * sub *
938
+ *******/
939
+
940
+ namespace wrap
941
+ {
942
+ // TODO(c++17): Make a single function with if constexpr switch
943
+ // Templating on the scalar type `T` is required because in some compilers (e.g. MSVC)
944
+ // the vector types are all aliases of the same type.
945
+ template <class T, std::enable_if_t<std::is_same<T, uint8_t>::value, int> = 0>
946
+ XSIMD_INLINE uint8x16_t x_vsubq(uint8x16_t a, uint8x16_t b) noexcept { return vsubq_u8(a, b); }
947
+ template <class T, std::enable_if_t<std::is_same<T, int8_t>::value, int> = 0>
948
+ XSIMD_INLINE int8x16_t x_vsubq(int8x16_t a, int8x16_t b) noexcept { return vsubq_s8(a, b); }
949
+ template <class T, std::enable_if_t<std::is_same<T, uint16_t>::value, int> = 0>
950
+ XSIMD_INLINE uint16x8_t x_vsubq(uint16x8_t a, uint16x8_t b) noexcept { return vsubq_u16(a, b); }
951
+ template <class T, std::enable_if_t<std::is_same<T, int16_t>::value, int> = 0>
952
+ XSIMD_INLINE int16x8_t x_vsubq(int16x8_t a, int16x8_t b) noexcept { return vsubq_s16(a, b); }
953
+ template <class T, std::enable_if_t<std::is_same<T, uint32_t>::value, int> = 0>
954
+ XSIMD_INLINE uint32x4_t x_vsubq(uint32x4_t a, uint32x4_t b) noexcept { return vsubq_u32(a, b); }
955
+ template <class T, std::enable_if_t<std::is_same<T, int32_t>::value, int> = 0>
956
+ XSIMD_INLINE int32x4_t x_vsubq(int32x4_t a, int32x4_t b) noexcept { return vsubq_s32(a, b); }
957
+ template <class T, std::enable_if_t<std::is_same<T, uint64_t>::value, int> = 0>
958
+ XSIMD_INLINE uint64x2_t x_vsubq(uint64x2_t a, uint64x2_t b) noexcept { return vsubq_u64(a, b); }
959
+ template <class T, std::enable_if_t<std::is_same<T, int64_t>::value, int> = 0>
960
+ XSIMD_INLINE int64x2_t x_vsubq(int64x2_t a, int64x2_t b) noexcept { return vsubq_s64(a, b); }
961
+ template <class T, std::enable_if_t<std::is_same<T, float>::value, int> = 0>
962
+ XSIMD_INLINE float32x4_t x_vsubq(float32x4_t a, float32x4_t b) noexcept { return vsubq_f32(a, b); }
963
+ }
964
+
965
+ template <class A, class T, detail::enable_neon_type_t<T> = 0>
966
+ XSIMD_INLINE batch<T, A> sub(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon>) noexcept
967
+ {
968
+ using register_type = typename batch<T, A>::register_type;
969
+ return wrap::x_vsubq<map_to_sized_type_t<T>>(register_type(lhs), register_type(rhs));
970
+ }
971
+
972
+ /********
973
+ * ssub *
974
+ ********/
975
+
976
+ namespace wrap
977
+ {
978
+ // TODO(c++17): Make a single function with if constexpr switch
979
+ // Templating on the scalar type `T` is required because in some compilers (e.g. MSVC)
980
+ // the vector types are all aliases of the same type.
981
+ template <class T, std::enable_if_t<std::is_same<T, uint8_t>::value, int> = 0>
982
+ XSIMD_INLINE uint8x16_t x_vqsubq(uint8x16_t a, uint8x16_t b) noexcept { return vqsubq_u8(a, b); }
983
+ template <class T, std::enable_if_t<std::is_same<T, int8_t>::value, int> = 0>
984
+ XSIMD_INLINE int8x16_t x_vqsubq(int8x16_t a, int8x16_t b) noexcept { return vqsubq_s8(a, b); }
985
+ template <class T, std::enable_if_t<std::is_same<T, uint16_t>::value, int> = 0>
986
+ XSIMD_INLINE uint16x8_t x_vqsubq(uint16x8_t a, uint16x8_t b) noexcept { return vqsubq_u16(a, b); }
987
+ template <class T, std::enable_if_t<std::is_same<T, int16_t>::value, int> = 0>
988
+ XSIMD_INLINE int16x8_t x_vqsubq(int16x8_t a, int16x8_t b) noexcept { return vqsubq_s16(a, b); }
989
+ template <class T, std::enable_if_t<std::is_same<T, uint32_t>::value, int> = 0>
990
+ XSIMD_INLINE uint32x4_t x_vqsubq(uint32x4_t a, uint32x4_t b) noexcept { return vqsubq_u32(a, b); }
991
+ template <class T, std::enable_if_t<std::is_same<T, int32_t>::value, int> = 0>
992
+ XSIMD_INLINE int32x4_t x_vqsubq(int32x4_t a, int32x4_t b) noexcept { return vqsubq_s32(a, b); }
993
+ template <class T, std::enable_if_t<std::is_same<T, uint64_t>::value, int> = 0>
994
+ XSIMD_INLINE uint64x2_t x_vqsubq(uint64x2_t a, uint64x2_t b) noexcept { return vqsubq_u64(a, b); }
995
+ template <class T, std::enable_if_t<std::is_same<T, int64_t>::value, int> = 0>
996
+ XSIMD_INLINE int64x2_t x_vqsubq(int64x2_t a, int64x2_t b) noexcept { return vqsubq_s64(a, b); }
997
+ template <class T, std::enable_if_t<std::is_same<T, float>::value, int> = 0>
998
+ XSIMD_INLINE float32x4_t x_vqsubq(float32x4_t a, float32x4_t b) noexcept { return vsubq_f32(a, b); }
999
+ }
1000
+
1001
+ template <class A, class T, detail::enable_neon_type_t<T> = 0>
1002
+ XSIMD_INLINE batch<T, A> ssub(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon>) noexcept
1003
+ {
1004
+ using register_type = typename batch<T, A>::register_type;
1005
+ return wrap::x_vqsubq<map_to_sized_type_t<T>>(register_type(lhs), register_type(rhs));
1006
+ }
1007
+
1008
+ /*******
1009
+ * mul *
1010
+ *******/
1011
+
1012
+ namespace wrap
1013
+ {
1014
+ // TODO(c++17): Make a single function with if constexpr switch
1015
+ // Templating on the scalar type `T` is required because in some compilers (e.g. MSVC)
1016
+ // the vector types are all aliases of the same type.
1017
+ template <class T, std::enable_if_t<std::is_same<T, uint8_t>::value, int> = 0>
1018
+ XSIMD_INLINE uint8x16_t x_vmulq(uint8x16_t a, uint8x16_t b) noexcept { return vmulq_u8(a, b); }
1019
+ template <class T, std::enable_if_t<std::is_same<T, int8_t>::value, int> = 0>
1020
+ XSIMD_INLINE int8x16_t x_vmulq(int8x16_t a, int8x16_t b) noexcept { return vmulq_s8(a, b); }
1021
+ template <class T, std::enable_if_t<std::is_same<T, uint16_t>::value, int> = 0>
1022
+ XSIMD_INLINE uint16x8_t x_vmulq(uint16x8_t a, uint16x8_t b) noexcept { return vmulq_u16(a, b); }
1023
+ template <class T, std::enable_if_t<std::is_same<T, int16_t>::value, int> = 0>
1024
+ XSIMD_INLINE int16x8_t x_vmulq(int16x8_t a, int16x8_t b) noexcept { return vmulq_s16(a, b); }
1025
+ template <class T, std::enable_if_t<std::is_same<T, uint32_t>::value, int> = 0>
1026
+ XSIMD_INLINE uint32x4_t x_vmulq(uint32x4_t a, uint32x4_t b) noexcept { return vmulq_u32(a, b); }
1027
+ template <class T, std::enable_if_t<std::is_same<T, int32_t>::value, int> = 0>
1028
+ XSIMD_INLINE int32x4_t x_vmulq(int32x4_t a, int32x4_t b) noexcept { return vmulq_s32(a, b); }
1029
+ template <class T, std::enable_if_t<std::is_same<T, float>::value, int> = 0>
1030
+ XSIMD_INLINE float32x4_t x_vmulq(float32x4_t a, float32x4_t b) noexcept { return vmulq_f32(a, b); }
1031
+ }
1032
+
1033
+ template <class A, class T, detail::exclude_int64_neon_t<T> = 0>
1034
+ XSIMD_INLINE batch<T, A> mul(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon>) noexcept
1035
+ {
1036
+ using register_type = typename batch<T, A>::register_type;
1037
+ return wrap::x_vmulq<map_to_sized_type_t<T>>(register_type(lhs), register_type(rhs));
1038
+ }
1039
+
1040
+ /*******
1041
+ * div *
1042
+ *******/
1043
+
1044
+ #if defined(XSIMD_FAST_INTEGER_DIVISION)
1045
+ template <class A, class T, detail::enable_sized_signed_t<T, 4> = 0>
1046
+ XSIMD_INLINE batch<T, A> div(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon>) noexcept
1047
+ {
1048
+ return vcvtq_s32_f32(vcvtq_f32_s32(lhs) / vcvtq_f32_s32(rhs));
1049
+ }
1050
+
1051
+ template <class A, class T, detail::enable_sized_unsigned_t<T, 4> = 0>
1052
+ XSIMD_INLINE batch<T, A> div(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon>) noexcept
1053
+ {
1054
+ return vcvtq_u32_f32(vcvtq_f32_u32(lhs) / vcvtq_f32_u32(rhs));
1055
+ }
1056
+ #endif
1057
+
1058
+ template <class A>
1059
+ XSIMD_INLINE batch<float, A> div(batch<float, A> const& lhs, batch<float, A> const& rhs, requires_arch<neon>) noexcept
1060
+ {
1061
+ // from stackoverflow & https://projectne10.github.io/Ne10/doc/NE10__divc_8neon_8c_source.html
1062
+ // get an initial estimate of 1/b.
1063
+ float32x4_t rcp = reciprocal(rhs);
1064
+
1065
+ // use a couple Newton-Raphson steps to refine the estimate. Depending on your
1066
+ // application's accuracy requirements, you may be able to get away with only
1067
+ // one refinement (instead of the two used here). Be sure to test!
1068
+ rcp = vmulq_f32(vrecpsq_f32(rhs, rcp), rcp);
1069
+ rcp = vmulq_f32(vrecpsq_f32(rhs, rcp), rcp);
1070
+
1071
+ // and finally, compute a / b = a * (1 / b)
1072
+ return vmulq_f32(lhs, rcp);
1073
+ }
1074
+
1075
+ /******
1076
+ * eq *
1077
+ ******/
1078
+
1079
+ namespace wrap
1080
+ {
1081
+ // TODO(c++17): Make a single function with if constexpr switch
1082
+ // Templating on the scalar type `T` is required because in some compilers (e.g. MSVC)
1083
+ // the vector types are all aliases of the same type.
1084
+ template <class T, std::enable_if_t<std::is_same<T, uint8_t>::value, int> = 0>
1085
+ XSIMD_INLINE uint8x16_t x_vceqq(uint8x16_t a, uint8x16_t b) noexcept { return vceqq_u8(a, b); }
1086
+ template <class T, std::enable_if_t<std::is_same<T, int8_t>::value, int> = 0>
1087
+ XSIMD_INLINE uint8x16_t x_vceqq(int8x16_t a, int8x16_t b) noexcept { return vceqq_s8(a, b); }
1088
+ template <class T, std::enable_if_t<std::is_same<T, uint16_t>::value, int> = 0>
1089
+ XSIMD_INLINE uint16x8_t x_vceqq(uint16x8_t a, uint16x8_t b) noexcept { return vceqq_u16(a, b); }
1090
+ template <class T, std::enable_if_t<std::is_same<T, int16_t>::value, int> = 0>
1091
+ XSIMD_INLINE uint16x8_t x_vceqq(int16x8_t a, int16x8_t b) noexcept { return vceqq_s16(a, b); }
1092
+ template <class T, std::enable_if_t<std::is_same<T, uint32_t>::value, int> = 0>
1093
+ XSIMD_INLINE uint32x4_t x_vceqq(uint32x4_t a, uint32x4_t b) noexcept { return vceqq_u32(a, b); }
1094
+ template <class T, std::enable_if_t<std::is_same<T, int32_t>::value, int> = 0>
1095
+ XSIMD_INLINE uint32x4_t x_vceqq(int32x4_t a, int32x4_t b) noexcept { return vceqq_s32(a, b); }
1096
+ template <class T, std::enable_if_t<std::is_same<T, float>::value, int> = 0>
1097
+ XSIMD_INLINE uint32x4_t x_vceqq(float32x4_t a, float32x4_t b) noexcept { return vceqq_f32(a, b); }
1098
+ }
1099
+
1100
+ template <class A, class T, detail::exclude_int64_neon_t<T> = 0>
1101
+ XSIMD_INLINE batch_bool<T, A> eq(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon>) noexcept
1102
+ {
1103
+ using register_type = typename batch<T, A>::register_type;
1104
+ return wrap::x_vceqq<map_to_sized_type_t<T>>(register_type(lhs), register_type(rhs));
1105
+ }
1106
+
1107
+ template <class A, class T, detail::exclude_int64_neon_t<T> = 0>
1108
+ XSIMD_INLINE batch_bool<T, A> eq(batch_bool<T, A> const& lhs, batch_bool<T, A> const& rhs, requires_arch<neon>) noexcept
1109
+ {
1110
+ using register_type = typename batch_bool<T, A>::register_type;
1111
+ return wrap::x_vceqq<sized_uint_t<sizeof(T)>>(register_type(lhs), register_type(rhs));
1112
+ }
1113
+
1114
+ template <class A, class T, detail::enable_sized_unsigned_t<T, 8> = 0>
1115
+ XSIMD_INLINE batch_bool<T, A> eq(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon>) noexcept
1116
+ {
1117
+ auto eq32 = vceqq_u32(vreinterpretq_u32_u64(lhs.data), vreinterpretq_u32_u64(rhs.data));
1118
+ auto rev32 = vrev64q_u32(eq32);
1119
+ auto eq64 = vandq_u32(eq32, rev32);
1120
+ return batch_bool<T, A>(vreinterpretq_u64_u32(eq64));
1121
+ }
1122
+
1123
+ template <class A, class T, detail::enable_sized_signed_t<T, 8> = 0>
1124
+ XSIMD_INLINE batch_bool<T, A> eq(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon>) noexcept
1125
+ {
1126
+ auto eq32 = vceqq_u32(vreinterpretq_u32_s64(lhs.data), vreinterpretq_u32_s64(rhs.data));
1127
+ auto rev32 = vrev64q_u32(eq32);
1128
+ auto eq64 = vandq_u32(eq32, rev32);
1129
+ return batch_bool<T, A>(vreinterpretq_u64_u32(eq64));
1130
+ }
1131
+
1132
+ template <class A, class T, detail::enable_sized_integral_t<T, 8> = 0>
1133
+ XSIMD_INLINE batch_bool<T, A> eq(batch_bool<T, A> const& lhs, batch_bool<T, A> const& rhs, requires_arch<neon>) noexcept
1134
+ {
1135
+ return eq(batch<T, A> { lhs.data }, batch<T, A> { rhs.data }, A {});
1136
+ }
1137
+
1138
+ /*************
1139
+ * fast_cast *
1140
+ *************/
1141
+
1142
+ namespace detail
1143
+ {
1144
+ template <class A>
1145
+ XSIMD_INLINE batch<float, A> fast_cast(batch<int32_t, A> const& self, batch<float, A> const&, requires_arch<neon>) noexcept
1146
+ {
1147
+ return vcvtq_f32_s32(self);
1148
+ }
1149
+
1150
+ template <class A>
1151
+ XSIMD_INLINE batch<float, A> fast_cast(batch<uint32_t, A> const& self, batch<float, A> const&, requires_arch<neon>) noexcept
1152
+ {
1153
+ return vcvtq_f32_u32(self);
1154
+ }
1155
+
1156
+ template <class A>
1157
+ XSIMD_INLINE batch<int32_t, A> fast_cast(batch<float, A> const& self, batch<int32_t, A> const&, requires_arch<neon>) noexcept
1158
+ {
1159
+ return vcvtq_s32_f32(self);
1160
+ }
1161
+
1162
+ template <class A>
1163
+ XSIMD_INLINE batch<uint32_t, A> fast_cast(batch<float, A> const& self, batch<uint32_t, A> const&, requires_arch<neon>) noexcept
1164
+ {
1165
+ return vcvtq_u32_f32(self);
1166
+ }
1167
+
1168
+ }
1169
+
1170
+ /******
1171
+ * lt *
1172
+ ******/
1173
+
1174
+ namespace wrap
1175
+ {
1176
+ // TODO(c++17): Make a single function with if constexpr switch
1177
+ // Templating on the scalar type `T` is required because in some compilers (e.g. MSVC)
1178
+ // the vector types are all aliases of the same type.
1179
+ template <class T, std::enable_if_t<std::is_same<T, uint8_t>::value, int> = 0>
1180
+ XSIMD_INLINE uint8x16_t x_vcltq(uint8x16_t a, uint8x16_t b) noexcept { return vcltq_u8(a, b); }
1181
+ template <class T, std::enable_if_t<std::is_same<T, int8_t>::value, int> = 0>
1182
+ XSIMD_INLINE uint8x16_t x_vcltq(int8x16_t a, int8x16_t b) noexcept { return vcltq_s8(a, b); }
1183
+ template <class T, std::enable_if_t<std::is_same<T, uint16_t>::value, int> = 0>
1184
+ XSIMD_INLINE uint16x8_t x_vcltq(uint16x8_t a, uint16x8_t b) noexcept { return vcltq_u16(a, b); }
1185
+ template <class T, std::enable_if_t<std::is_same<T, int16_t>::value, int> = 0>
1186
+ XSIMD_INLINE uint16x8_t x_vcltq(int16x8_t a, int16x8_t b) noexcept { return vcltq_s16(a, b); }
1187
+ template <class T, std::enable_if_t<std::is_same<T, uint32_t>::value, int> = 0>
1188
+ XSIMD_INLINE uint32x4_t x_vcltq(uint32x4_t a, uint32x4_t b) noexcept { return vcltq_u32(a, b); }
1189
+ template <class T, std::enable_if_t<std::is_same<T, int32_t>::value, int> = 0>
1190
+ XSIMD_INLINE uint32x4_t x_vcltq(int32x4_t a, int32x4_t b) noexcept { return vcltq_s32(a, b); }
1191
+ template <class T, std::enable_if_t<std::is_same<T, float>::value, int> = 0>
1192
+ XSIMD_INLINE uint32x4_t x_vcltq(float32x4_t a, float32x4_t b) noexcept { return vcltq_f32(a, b); }
1193
+ }
1194
+
1195
+ template <class A, class T, detail::exclude_int64_neon_t<T> = 0>
1196
+ XSIMD_INLINE batch_bool<T, A> lt(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon>) noexcept
1197
+ {
1198
+ using register_type = typename batch<T, A>::register_type;
1199
+ return wrap::x_vcltq<map_to_sized_type_t<T>>(register_type(lhs), register_type(rhs));
1200
+ }
1201
+
1202
+ template <class A, class T, detail::enable_sized_signed_t<T, 8> = 0>
1203
+ XSIMD_INLINE batch_bool<T, A> lt(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon>) noexcept
1204
+ {
1205
+ using register_type = typename batch<T, A>::register_type;
1206
+ return batch_bool<T, A>(vreinterpretq_u64_s64(vshrq_n_s64(vqsubq_s64(register_type(lhs), register_type(rhs)), 63)));
1207
+ }
1208
+
1209
+ template <class A, class T, detail::enable_sized_unsigned_t<T, 8> = 0>
1210
+ XSIMD_INLINE batch_bool<T, A> lt(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon>) noexcept
1211
+ {
1212
+ using register_type = typename batch<T, A>::register_type;
1213
+ register_type acc = { 0x7FFFFFFFFFFFFFFFull, 0x7FFFFFFFFFFFFFFFull };
1214
+ return batch_bool<T, A>(vreinterpretq_u64_s64(vshrq_n_s64(vreinterpretq_s64_u64(vqaddq_u64(vqsubq_u64(register_type(rhs), register_type(lhs)), acc)), 63)));
1215
+ }
1216
+
1217
+ /******
1218
+ * le *
1219
+ ******/
1220
+
1221
+ namespace wrap
1222
+ {
1223
+ // TODO(c++17): Make a single function with if constexpr switch
1224
+ // Templating on the scalar type `T` is required because in some compilers (e.g. MSVC)
1225
+ // the vector types are all aliases of the same type.
1226
+ template <class T, std::enable_if_t<std::is_same<T, uint8_t>::value, int> = 0>
1227
+ XSIMD_INLINE uint8x16_t x_vcleq(uint8x16_t a, uint8x16_t b) noexcept { return vcleq_u8(a, b); }
1228
+ template <class T, std::enable_if_t<std::is_same<T, int8_t>::value, int> = 0>
1229
+ XSIMD_INLINE uint8x16_t x_vcleq(int8x16_t a, int8x16_t b) noexcept { return vcleq_s8(a, b); }
1230
+ template <class T, std::enable_if_t<std::is_same<T, uint16_t>::value, int> = 0>
1231
+ XSIMD_INLINE uint16x8_t x_vcleq(uint16x8_t a, uint16x8_t b) noexcept { return vcleq_u16(a, b); }
1232
+ template <class T, std::enable_if_t<std::is_same<T, int16_t>::value, int> = 0>
1233
+ XSIMD_INLINE uint16x8_t x_vcleq(int16x8_t a, int16x8_t b) noexcept { return vcleq_s16(a, b); }
1234
+ template <class T, std::enable_if_t<std::is_same<T, uint32_t>::value, int> = 0>
1235
+ XSIMD_INLINE uint32x4_t x_vcleq(uint32x4_t a, uint32x4_t b) noexcept { return vcleq_u32(a, b); }
1236
+ template <class T, std::enable_if_t<std::is_same<T, int32_t>::value, int> = 0>
1237
+ XSIMD_INLINE uint32x4_t x_vcleq(int32x4_t a, int32x4_t b) noexcept { return vcleq_s32(a, b); }
1238
+ template <class T, std::enable_if_t<std::is_same<T, float>::value, int> = 0>
1239
+ XSIMD_INLINE uint32x4_t x_vcleq(float32x4_t a, float32x4_t b) noexcept { return vcleq_f32(a, b); }
1240
+ }
1241
+
1242
+ template <class A, class T, detail::exclude_int64_neon_t<T> = 0>
1243
+ XSIMD_INLINE batch_bool<T, A> le(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon>) noexcept
1244
+ {
1245
+ using register_type = typename batch<T, A>::register_type;
1246
+ return wrap::x_vcleq<map_to_sized_type_t<T>>(register_type(lhs), register_type(rhs));
1247
+ }
1248
+
1249
+ template <class A, class T, detail::enable_sized_integral_t<T, 8> = 0>
1250
+ XSIMD_INLINE batch_bool<T, A> le(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon>) noexcept
1251
+ {
1252
+ return !(lhs > rhs);
1253
+ }
1254
+
1255
+ /******
1256
+ * gt *
1257
+ ******/
1258
+
1259
+ namespace wrap
1260
+ {
1261
+ // TODO(c++17): Make a single function with if constexpr switch
1262
+ // Templating on the scalar type `T` is required because in some compilers (e.g. MSVC)
1263
+ // the vector types are all aliases of the same type.
1264
+ template <class T, std::enable_if_t<std::is_same<T, uint8_t>::value, int> = 0>
1265
+ XSIMD_INLINE uint8x16_t x_vcgtq(uint8x16_t a, uint8x16_t b) noexcept { return vcgtq_u8(a, b); }
1266
+ template <class T, std::enable_if_t<std::is_same<T, int8_t>::value, int> = 0>
1267
+ XSIMD_INLINE uint8x16_t x_vcgtq(int8x16_t a, int8x16_t b) noexcept { return vcgtq_s8(a, b); }
1268
+ template <class T, std::enable_if_t<std::is_same<T, uint16_t>::value, int> = 0>
1269
+ XSIMD_INLINE uint16x8_t x_vcgtq(uint16x8_t a, uint16x8_t b) noexcept { return vcgtq_u16(a, b); }
1270
+ template <class T, std::enable_if_t<std::is_same<T, int16_t>::value, int> = 0>
1271
+ XSIMD_INLINE uint16x8_t x_vcgtq(int16x8_t a, int16x8_t b) noexcept { return vcgtq_s16(a, b); }
1272
+ template <class T, std::enable_if_t<std::is_same<T, uint32_t>::value, int> = 0>
1273
+ XSIMD_INLINE uint32x4_t x_vcgtq(uint32x4_t a, uint32x4_t b) noexcept { return vcgtq_u32(a, b); }
1274
+ template <class T, std::enable_if_t<std::is_same<T, int32_t>::value, int> = 0>
1275
+ XSIMD_INLINE uint32x4_t x_vcgtq(int32x4_t a, int32x4_t b) noexcept { return vcgtq_s32(a, b); }
1276
+ template <class T, std::enable_if_t<std::is_same<T, float>::value, int> = 0>
1277
+ XSIMD_INLINE uint32x4_t x_vcgtq(float32x4_t a, float32x4_t b) noexcept { return vcgtq_f32(a, b); }
1278
+ }
1279
+
1280
+ template <class A, class T, detail::exclude_int64_neon_t<T> = 0>
1281
+ XSIMD_INLINE batch_bool<T, A> gt(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon>) noexcept
1282
+ {
1283
+ using register_type = typename batch<T, A>::register_type;
1284
+ return wrap::x_vcgtq<map_to_sized_type_t<T>>(register_type(lhs), register_type(rhs));
1285
+ }
1286
+
1287
+ template <class A, class T, detail::enable_sized_signed_t<T, 8> = 0>
1288
+ XSIMD_INLINE batch_bool<T, A> gt(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon>) noexcept
1289
+ {
1290
+ using register_type = typename batch<T, A>::register_type;
1291
+ return batch_bool<T, A>(vreinterpretq_u64_s64(vshrq_n_s64(vqsubq_s64(register_type(rhs), register_type(lhs)), 63)));
1292
+ }
1293
+
1294
+ template <class A, class T, detail::enable_sized_unsigned_t<T, 8> = 0>
1295
+ XSIMD_INLINE batch_bool<T, A> gt(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon>) noexcept
1296
+ {
1297
+ using register_type = typename batch<T, A>::register_type;
1298
+ register_type acc = { 0x7FFFFFFFFFFFFFFFull, 0x7FFFFFFFFFFFFFFFull };
1299
+ return batch_bool<T, A>(vreinterpretq_u64_s64(vshrq_n_s64(vreinterpretq_s64_u64(vqaddq_u64(vqsubq_u64(register_type(lhs), register_type(rhs)), acc)), 63)));
1300
+ }
1301
+
1302
+ /******
1303
+ * ge *
1304
+ ******/
1305
+
1306
+ namespace wrap
1307
+ {
1308
+ // TODO(c++17): Make a single function with if constexpr switch
1309
+ // Templating on the scalar type `T` is required because in some compilers (e.g. MSVC)
1310
+ // the vector types are all aliases of the same type.
1311
+ template <class T, std::enable_if_t<std::is_same<T, uint8_t>::value, int> = 0>
1312
+ XSIMD_INLINE uint8x16_t x_vcgeq(uint8x16_t a, uint8x16_t b) noexcept { return vcgeq_u8(a, b); }
1313
+ template <class T, std::enable_if_t<std::is_same<T, int8_t>::value, int> = 0>
1314
+ XSIMD_INLINE uint8x16_t x_vcgeq(int8x16_t a, int8x16_t b) noexcept { return vcgeq_s8(a, b); }
1315
+ template <class T, std::enable_if_t<std::is_same<T, uint16_t>::value, int> = 0>
1316
+ XSIMD_INLINE uint16x8_t x_vcgeq(uint16x8_t a, uint16x8_t b) noexcept { return vcgeq_u16(a, b); }
1317
+ template <class T, std::enable_if_t<std::is_same<T, int16_t>::value, int> = 0>
1318
+ XSIMD_INLINE uint16x8_t x_vcgeq(int16x8_t a, int16x8_t b) noexcept { return vcgeq_s16(a, b); }
1319
+ template <class T, std::enable_if_t<std::is_same<T, uint32_t>::value, int> = 0>
1320
+ XSIMD_INLINE uint32x4_t x_vcgeq(uint32x4_t a, uint32x4_t b) noexcept { return vcgeq_u32(a, b); }
1321
+ template <class T, std::enable_if_t<std::is_same<T, int32_t>::value, int> = 0>
1322
+ XSIMD_INLINE uint32x4_t x_vcgeq(int32x4_t a, int32x4_t b) noexcept { return vcgeq_s32(a, b); }
1323
+ template <class T, std::enable_if_t<std::is_same<T, float>::value, int> = 0>
1324
+ XSIMD_INLINE uint32x4_t x_vcgeq(float32x4_t a, float32x4_t b) noexcept { return vcgeq_f32(a, b); }
1325
+ }
1326
+
1327
+ template <class A, class T, detail::exclude_int64_neon_t<T> = 0>
1328
+ XSIMD_INLINE batch_bool<T, A> ge(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon>) noexcept
1329
+ {
1330
+ using register_type = typename batch<T, A>::register_type;
1331
+ return wrap::x_vcgeq<map_to_sized_type_t<T>>(register_type(lhs), register_type(rhs));
1332
+ }
1333
+
1334
+ template <class A, class T, detail::enable_sized_integral_t<T, 8> = 0>
1335
+ XSIMD_INLINE batch_bool<T, A> ge(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon>) noexcept
1336
+ {
1337
+ return !(lhs < rhs);
1338
+ }
1339
+
1340
+ /*******************
1341
+ * batch_bool_cast *
1342
+ *******************/
1343
+
1344
+ template <class A, class T_out, class T_in>
1345
+ 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<neon>) noexcept
1346
+ {
1347
+ using register_type = typename batch_bool<T_out, A>::register_type;
1348
+ return register_type(self);
1349
+ }
1350
+
1351
+ /***************
1352
+ * bitwise_and *
1353
+ ***************/
1354
+
1355
+ namespace wrap
1356
+ {
1357
+ // TODO(c++17): Make a single function with if constexpr switch
1358
+ // Templating on the scalar type `T` is required because in some compilers (e.g. MSVC)
1359
+ // the vector types are all aliases of the same type.
1360
+ template <class T, std::enable_if_t<std::is_same<T, uint8_t>::value, int> = 0>
1361
+ XSIMD_INLINE uint8x16_t x_vandq(uint8x16_t a, uint8x16_t b) noexcept { return vandq_u8(a, b); }
1362
+ template <class T, std::enable_if_t<std::is_same<T, int8_t>::value, int> = 0>
1363
+ XSIMD_INLINE int8x16_t x_vandq(int8x16_t a, int8x16_t b) noexcept { return vandq_s8(a, b); }
1364
+ template <class T, std::enable_if_t<std::is_same<T, uint16_t>::value, int> = 0>
1365
+ XSIMD_INLINE uint16x8_t x_vandq(uint16x8_t a, uint16x8_t b) noexcept { return vandq_u16(a, b); }
1366
+ template <class T, std::enable_if_t<std::is_same<T, int16_t>::value, int> = 0>
1367
+ XSIMD_INLINE int16x8_t x_vandq(int16x8_t a, int16x8_t b) noexcept { return vandq_s16(a, b); }
1368
+ template <class T, std::enable_if_t<std::is_same<T, uint32_t>::value, int> = 0>
1369
+ XSIMD_INLINE uint32x4_t x_vandq(uint32x4_t a, uint32x4_t b) noexcept { return vandq_u32(a, b); }
1370
+ template <class T, std::enable_if_t<std::is_same<T, int32_t>::value, int> = 0>
1371
+ XSIMD_INLINE int32x4_t x_vandq(int32x4_t a, int32x4_t b) noexcept { return vandq_s32(a, b); }
1372
+ template <class T, std::enable_if_t<std::is_same<T, uint64_t>::value, int> = 0>
1373
+ XSIMD_INLINE uint64x2_t x_vandq(uint64x2_t a, uint64x2_t b) noexcept { return vandq_u64(a, b); }
1374
+ template <class T, std::enable_if_t<std::is_same<T, int64_t>::value, int> = 0>
1375
+ XSIMD_INLINE int64x2_t x_vandq(int64x2_t a, int64x2_t b) noexcept { return vandq_s64(a, b); }
1376
+ template <class T, std::enable_if_t<std::is_same<T, float>::value, int> = 0>
1377
+ XSIMD_INLINE float32x4_t x_vandq(float32x4_t a, float32x4_t b) noexcept
1378
+ {
1379
+ return vreinterpretq_f32_u32(vandq_u32(vreinterpretq_u32_f32(a),
1380
+ vreinterpretq_u32_f32(b)));
1381
+ }
1382
+ }
1383
+
1384
+ template <class A, class T, detail::enable_neon_type_t<T> = 0>
1385
+ XSIMD_INLINE batch<T, A> bitwise_and(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon>) noexcept
1386
+ {
1387
+ using register_type = typename batch<T, A>::register_type;
1388
+ return wrap::x_vandq<map_to_sized_type_t<T>>(register_type(lhs), register_type(rhs));
1389
+ }
1390
+
1391
+ template <class A, class T, detail::enable_neon_type_t<T> = 0>
1392
+ XSIMD_INLINE batch_bool<T, A> bitwise_and(batch_bool<T, A> const& lhs, batch_bool<T, A> const& rhs, requires_arch<neon>) noexcept
1393
+ {
1394
+ using register_type = typename batch_bool<T, A>::register_type;
1395
+ return wrap::x_vandq<sized_uint_t<sizeof(T)>>(register_type(lhs), register_type(rhs));
1396
+ }
1397
+
1398
+ /**************
1399
+ * bitwise_or *
1400
+ **************/
1401
+
1402
+ namespace wrap
1403
+ {
1404
+ // TODO(c++17): Make a single function with if constexpr switch
1405
+ // Templating on the scalar type `T` is required because in some compilers (e.g. MSVC)
1406
+ // the vector types are all aliases of the same type.
1407
+ template <class T, std::enable_if_t<std::is_same<T, uint8_t>::value, int> = 0>
1408
+ XSIMD_INLINE uint8x16_t x_vorrq(uint8x16_t a, uint8x16_t b) noexcept { return vorrq_u8(a, b); }
1409
+ template <class T, std::enable_if_t<std::is_same<T, int8_t>::value, int> = 0>
1410
+ XSIMD_INLINE int8x16_t x_vorrq(int8x16_t a, int8x16_t b) noexcept { return vorrq_s8(a, b); }
1411
+ template <class T, std::enable_if_t<std::is_same<T, uint16_t>::value, int> = 0>
1412
+ XSIMD_INLINE uint16x8_t x_vorrq(uint16x8_t a, uint16x8_t b) noexcept { return vorrq_u16(a, b); }
1413
+ template <class T, std::enable_if_t<std::is_same<T, int16_t>::value, int> = 0>
1414
+ XSIMD_INLINE int16x8_t x_vorrq(int16x8_t a, int16x8_t b) noexcept { return vorrq_s16(a, b); }
1415
+ template <class T, std::enable_if_t<std::is_same<T, uint32_t>::value, int> = 0>
1416
+ XSIMD_INLINE uint32x4_t x_vorrq(uint32x4_t a, uint32x4_t b) noexcept { return vorrq_u32(a, b); }
1417
+ template <class T, std::enable_if_t<std::is_same<T, int32_t>::value, int> = 0>
1418
+ XSIMD_INLINE int32x4_t x_vorrq(int32x4_t a, int32x4_t b) noexcept { return vorrq_s32(a, b); }
1419
+ template <class T, std::enable_if_t<std::is_same<T, uint64_t>::value, int> = 0>
1420
+ XSIMD_INLINE uint64x2_t x_vorrq(uint64x2_t a, uint64x2_t b) noexcept { return vorrq_u64(a, b); }
1421
+ template <class T, std::enable_if_t<std::is_same<T, int64_t>::value, int> = 0>
1422
+ XSIMD_INLINE int64x2_t x_vorrq(int64x2_t a, int64x2_t b) noexcept { return vorrq_s64(a, b); }
1423
+ template <class T, std::enable_if_t<std::is_same<T, float>::value, int> = 0>
1424
+ XSIMD_INLINE float32x4_t x_vorrq(float32x4_t a, float32x4_t b) noexcept
1425
+ {
1426
+ return vreinterpretq_f32_u32(vorrq_u32(vreinterpretq_u32_f32(a),
1427
+ vreinterpretq_u32_f32(b)));
1428
+ }
1429
+ }
1430
+
1431
+ template <class A, class T, detail::enable_neon_type_t<T> = 0>
1432
+ XSIMD_INLINE batch<T, A> bitwise_or(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon>) noexcept
1433
+ {
1434
+ using register_type = typename batch<T, A>::register_type;
1435
+ return wrap::x_vorrq<map_to_sized_type_t<T>>(register_type(lhs), register_type(rhs));
1436
+ }
1437
+
1438
+ template <class A, class T, detail::enable_neon_type_t<T> = 0>
1439
+ XSIMD_INLINE batch_bool<T, A> bitwise_or(batch_bool<T, A> const& lhs, batch_bool<T, A> const& rhs, requires_arch<neon>) noexcept
1440
+ {
1441
+ using register_type = typename batch_bool<T, A>::register_type;
1442
+ return wrap::x_vorrq<sized_uint_t<sizeof(T)>>(register_type(lhs), register_type(rhs));
1443
+ }
1444
+
1445
+ /***************
1446
+ * bitwise_xor *
1447
+ ***************/
1448
+
1449
+ namespace wrap
1450
+ {
1451
+ // TODO(c++17): Make a single function with if constexpr switch
1452
+ // Templating on the scalar type `T` is required because in some compilers (e.g. MSVC)
1453
+ // the vector types are all aliases of the same type.
1454
+ template <class T, std::enable_if_t<std::is_same<T, uint8_t>::value, int> = 0>
1455
+ XSIMD_INLINE uint8x16_t x_veorq(uint8x16_t a, uint8x16_t b) noexcept { return veorq_u8(a, b); }
1456
+ template <class T, std::enable_if_t<std::is_same<T, int8_t>::value, int> = 0>
1457
+ XSIMD_INLINE int8x16_t x_veorq(int8x16_t a, int8x16_t b) noexcept { return veorq_s8(a, b); }
1458
+ template <class T, std::enable_if_t<std::is_same<T, uint16_t>::value, int> = 0>
1459
+ XSIMD_INLINE uint16x8_t x_veorq(uint16x8_t a, uint16x8_t b) noexcept { return veorq_u16(a, b); }
1460
+ template <class T, std::enable_if_t<std::is_same<T, int16_t>::value, int> = 0>
1461
+ XSIMD_INLINE int16x8_t x_veorq(int16x8_t a, int16x8_t b) noexcept { return veorq_s16(a, b); }
1462
+ template <class T, std::enable_if_t<std::is_same<T, uint32_t>::value, int> = 0>
1463
+ XSIMD_INLINE uint32x4_t x_veorq(uint32x4_t a, uint32x4_t b) noexcept { return veorq_u32(a, b); }
1464
+ template <class T, std::enable_if_t<std::is_same<T, int32_t>::value, int> = 0>
1465
+ XSIMD_INLINE int32x4_t x_veorq(int32x4_t a, int32x4_t b) noexcept { return veorq_s32(a, b); }
1466
+ template <class T, std::enable_if_t<std::is_same<T, uint64_t>::value, int> = 0>
1467
+ XSIMD_INLINE uint64x2_t x_veorq(uint64x2_t a, uint64x2_t b) noexcept { return veorq_u64(a, b); }
1468
+ template <class T, std::enable_if_t<std::is_same<T, int64_t>::value, int> = 0>
1469
+ XSIMD_INLINE int64x2_t x_veorq(int64x2_t a, int64x2_t b) noexcept { return veorq_s64(a, b); }
1470
+ template <class T, std::enable_if_t<std::is_same<T, float>::value, int> = 0>
1471
+ XSIMD_INLINE float32x4_t x_veorq(float32x4_t a, float32x4_t b) noexcept
1472
+ {
1473
+ return vreinterpretq_f32_u32(veorq_u32(vreinterpretq_u32_f32(a),
1474
+ vreinterpretq_u32_f32(b)));
1475
+ }
1476
+ }
1477
+
1478
+ template <class A, class T, detail::enable_neon_type_t<T> = 0>
1479
+ XSIMD_INLINE batch<T, A> bitwise_xor(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon>) noexcept
1480
+ {
1481
+ using register_type = typename batch<T, A>::register_type;
1482
+ return wrap::x_veorq<map_to_sized_type_t<T>>(register_type(lhs), register_type(rhs));
1483
+ }
1484
+
1485
+ template <class A, class T, detail::enable_neon_type_t<T> = 0>
1486
+ XSIMD_INLINE batch_bool<T, A> bitwise_xor(batch_bool<T, A> const& lhs, batch_bool<T, A> const& rhs, requires_arch<neon>) noexcept
1487
+ {
1488
+ using register_type = typename batch_bool<T, A>::register_type;
1489
+ return wrap::x_veorq<sized_uint_t<sizeof(T)>>(register_type(lhs), register_type(rhs));
1490
+ }
1491
+
1492
+ /*******
1493
+ * neq *
1494
+ *******/
1495
+
1496
+ template <class A, class T>
1497
+ XSIMD_INLINE batch_bool<T, A> neq(batch_bool<T, A> const& lhs, batch_bool<T, A> const& rhs, requires_arch<neon>) noexcept
1498
+ {
1499
+ return bitwise_xor(lhs, rhs, A {});
1500
+ }
1501
+
1502
+ /***************
1503
+ * bitwise_not *
1504
+ ***************/
1505
+
1506
+ namespace wrap
1507
+ {
1508
+ // TODO(c++17): Make a single function with if constexpr switch
1509
+ // Templating on the scalar type `T` is required because in some compilers (e.g. MSVC)
1510
+ // the vector types are all aliases of the same type.
1511
+ template <class T, std::enable_if_t<std::is_same<T, uint8_t>::value, int> = 0>
1512
+ XSIMD_INLINE uint8x16_t x_vmvnq(uint8x16_t a) noexcept { return vmvnq_u8(a); }
1513
+ template <class T, std::enable_if_t<std::is_same<T, int8_t>::value, int> = 0>
1514
+ XSIMD_INLINE int8x16_t x_vmvnq(int8x16_t a) noexcept { return vmvnq_s8(a); }
1515
+ template <class T, std::enable_if_t<std::is_same<T, uint16_t>::value, int> = 0>
1516
+ XSIMD_INLINE uint16x8_t x_vmvnq(uint16x8_t a) noexcept { return vmvnq_u16(a); }
1517
+ template <class T, std::enable_if_t<std::is_same<T, int16_t>::value, int> = 0>
1518
+ XSIMD_INLINE int16x8_t x_vmvnq(int16x8_t a) noexcept { return vmvnq_s16(a); }
1519
+ template <class T, std::enable_if_t<std::is_same<T, uint32_t>::value, int> = 0>
1520
+ XSIMD_INLINE uint32x4_t x_vmvnq(uint32x4_t a) noexcept { return vmvnq_u32(a); }
1521
+ template <class T, std::enable_if_t<std::is_same<T, int32_t>::value, int> = 0>
1522
+ XSIMD_INLINE int32x4_t x_vmvnq(int32x4_t a) noexcept { return vmvnq_s32(a); }
1523
+ template <class T, std::enable_if_t<std::is_same<T, uint64_t>::value, int> = 0>
1524
+ XSIMD_INLINE uint64x2_t x_vmvnq(uint64x2_t a) noexcept
1525
+ {
1526
+ return vreinterpretq_u64_u32(vmvnq_u32(vreinterpretq_u32_u64(a)));
1527
+ }
1528
+ template <class T, std::enable_if_t<std::is_same<T, int64_t>::value, int> = 0>
1529
+ XSIMD_INLINE int64x2_t x_vmvnq(int64x2_t a) noexcept
1530
+ {
1531
+ return vreinterpretq_s64_s32(vmvnq_s32(vreinterpretq_s32_s64(a)));
1532
+ }
1533
+ template <class T, std::enable_if_t<std::is_same<T, float>::value, int> = 0>
1534
+ XSIMD_INLINE float32x4_t x_vmvnq(float32x4_t a) noexcept
1535
+ {
1536
+ return vreinterpretq_f32_u32(vmvnq_u32(vreinterpretq_u32_f32(a)));
1537
+ }
1538
+ }
1539
+
1540
+ template <class A, class T, detail::enable_neon_type_t<T> = 0>
1541
+ XSIMD_INLINE batch<T, A> bitwise_not(batch<T, A> const& arg, requires_arch<neon>) noexcept
1542
+ {
1543
+ using register_type = typename batch<T, A>::register_type;
1544
+ return wrap::x_vmvnq<map_to_sized_type_t<T>>(register_type(arg));
1545
+ }
1546
+
1547
+ template <class A, class T, detail::enable_neon_type_t<T> = 0>
1548
+ XSIMD_INLINE batch_bool<T, A> bitwise_not(batch_bool<T, A> const& arg, requires_arch<neon>) noexcept
1549
+ {
1550
+ using register_type = typename batch_bool<T, A>::register_type;
1551
+ return wrap::x_vmvnq<sized_uint_t<sizeof(T)>>(register_type(arg));
1552
+ }
1553
+
1554
+ /******************
1555
+ * bitwise_andnot *
1556
+ ******************/
1557
+
1558
+ namespace wrap
1559
+ {
1560
+ // TODO(c++17): Make a single function with if constexpr switch
1561
+ // Templating on the scalar type `T` is required because in some compilers (e.g. MSVC)
1562
+ // the vector types are all aliases of the same type.
1563
+ template <class T, std::enable_if_t<std::is_same<T, uint8_t>::value, int> = 0>
1564
+ XSIMD_INLINE uint8x16_t x_vbicq(uint8x16_t a, uint8x16_t b) noexcept { return vbicq_u8(a, b); }
1565
+ template <class T, std::enable_if_t<std::is_same<T, int8_t>::value, int> = 0>
1566
+ XSIMD_INLINE int8x16_t x_vbicq(int8x16_t a, int8x16_t b) noexcept { return vbicq_s8(a, b); }
1567
+ template <class T, std::enable_if_t<std::is_same<T, uint16_t>::value, int> = 0>
1568
+ XSIMD_INLINE uint16x8_t x_vbicq(uint16x8_t a, uint16x8_t b) noexcept { return vbicq_u16(a, b); }
1569
+ template <class T, std::enable_if_t<std::is_same<T, int16_t>::value, int> = 0>
1570
+ XSIMD_INLINE int16x8_t x_vbicq(int16x8_t a, int16x8_t b) noexcept { return vbicq_s16(a, b); }
1571
+ template <class T, std::enable_if_t<std::is_same<T, uint32_t>::value, int> = 0>
1572
+ XSIMD_INLINE uint32x4_t x_vbicq(uint32x4_t a, uint32x4_t b) noexcept { return vbicq_u32(a, b); }
1573
+ template <class T, std::enable_if_t<std::is_same<T, int32_t>::value, int> = 0>
1574
+ XSIMD_INLINE int32x4_t x_vbicq(int32x4_t a, int32x4_t b) noexcept { return vbicq_s32(a, b); }
1575
+ template <class T, std::enable_if_t<std::is_same<T, uint64_t>::value, int> = 0>
1576
+ XSIMD_INLINE uint64x2_t x_vbicq(uint64x2_t a, uint64x2_t b) noexcept { return vbicq_u64(a, b); }
1577
+ template <class T, std::enable_if_t<std::is_same<T, int64_t>::value, int> = 0>
1578
+ XSIMD_INLINE int64x2_t x_vbicq(int64x2_t a, int64x2_t b) noexcept { return vbicq_s64(a, b); }
1579
+ template <class T, std::enable_if_t<std::is_same<T, float>::value, int> = 0>
1580
+ XSIMD_INLINE float32x4_t x_vbicq(float32x4_t a, float32x4_t b) noexcept
1581
+ {
1582
+ return vreinterpretq_f32_u32(vbicq_u32(vreinterpretq_u32_f32(a), vreinterpretq_u32_f32(b)));
1583
+ }
1584
+ }
1585
+
1586
+ template <class A, class T, detail::enable_neon_type_t<T> = 0>
1587
+ XSIMD_INLINE batch<T, A> bitwise_andnot(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon>) noexcept
1588
+ {
1589
+ using register_type = typename batch<T, A>::register_type;
1590
+ return wrap::x_vbicq<map_to_sized_type_t<T>>(register_type(lhs), register_type(rhs));
1591
+ }
1592
+
1593
+ template <class A, class T, detail::enable_neon_type_t<T> = 0>
1594
+ XSIMD_INLINE batch_bool<T, A> bitwise_andnot(batch_bool<T, A> const& lhs, batch_bool<T, A> const& rhs, requires_arch<neon>) noexcept
1595
+ {
1596
+ using register_type = typename batch_bool<T, A>::register_type;
1597
+ return wrap::x_vbicq<sized_uint_t<sizeof(T)>>(register_type(lhs), register_type(rhs));
1598
+ }
1599
+
1600
+ /*******
1601
+ * min *
1602
+ *******/
1603
+
1604
+ namespace wrap
1605
+ {
1606
+ // TODO(c++17): Make a single function with if constexpr switch
1607
+ // Templating on the scalar type `T` is required because in some compilers (e.g. MSVC)
1608
+ // the vector types are all aliases of the same type.
1609
+ template <class T, std::enable_if_t<std::is_same<T, uint8_t>::value, int> = 0>
1610
+ XSIMD_INLINE uint8x16_t x_vminq(uint8x16_t a, uint8x16_t b) noexcept { return vminq_u8(a, b); }
1611
+ template <class T, std::enable_if_t<std::is_same<T, int8_t>::value, int> = 0>
1612
+ XSIMD_INLINE int8x16_t x_vminq(int8x16_t a, int8x16_t b) noexcept { return vminq_s8(a, b); }
1613
+ template <class T, std::enable_if_t<std::is_same<T, uint16_t>::value, int> = 0>
1614
+ XSIMD_INLINE uint16x8_t x_vminq(uint16x8_t a, uint16x8_t b) noexcept { return vminq_u16(a, b); }
1615
+ template <class T, std::enable_if_t<std::is_same<T, int16_t>::value, int> = 0>
1616
+ XSIMD_INLINE int16x8_t x_vminq(int16x8_t a, int16x8_t b) noexcept { return vminq_s16(a, b); }
1617
+ template <class T, std::enable_if_t<std::is_same<T, uint32_t>::value, int> = 0>
1618
+ XSIMD_INLINE uint32x4_t x_vminq(uint32x4_t a, uint32x4_t b) noexcept { return vminq_u32(a, b); }
1619
+ template <class T, std::enable_if_t<std::is_same<T, int32_t>::value, int> = 0>
1620
+ XSIMD_INLINE int32x4_t x_vminq(int32x4_t a, int32x4_t b) noexcept { return vminq_s32(a, b); }
1621
+ template <class T, std::enable_if_t<std::is_same<T, float>::value, int> = 0>
1622
+ XSIMD_INLINE float32x4_t x_vminq(float32x4_t a, float32x4_t b) noexcept { return vminq_f32(a, b); }
1623
+ }
1624
+
1625
+ template <class A, class T, detail::exclude_int64_neon_t<T> = 0>
1626
+ XSIMD_INLINE batch<T, A> min(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon>) noexcept
1627
+ {
1628
+ using register_type = typename batch<T, A>::register_type;
1629
+ return wrap::x_vminq<map_to_sized_type_t<T>>(register_type(lhs), register_type(rhs));
1630
+ }
1631
+
1632
+ template <class A, class T, detail::enable_sized_integral_t<T, 8> = 0>
1633
+ XSIMD_INLINE batch<T, A> min(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon>) noexcept
1634
+ {
1635
+ return select(lhs > rhs, rhs, lhs);
1636
+ }
1637
+
1638
+ /*******
1639
+ * max *
1640
+ *******/
1641
+
1642
+ namespace wrap
1643
+ {
1644
+ // TODO(c++17): Make a single function with if constexpr switch
1645
+ // Templating on the scalar type `T` is required because in some compilers (e.g. MSVC)
1646
+ // the vector types are all aliases of the same type.
1647
+ template <class T, std::enable_if_t<std::is_same<T, uint8_t>::value, int> = 0>
1648
+ XSIMD_INLINE uint8x16_t x_vmaxq(uint8x16_t a, uint8x16_t b) noexcept { return vmaxq_u8(a, b); }
1649
+ template <class T, std::enable_if_t<std::is_same<T, int8_t>::value, int> = 0>
1650
+ XSIMD_INLINE int8x16_t x_vmaxq(int8x16_t a, int8x16_t b) noexcept { return vmaxq_s8(a, b); }
1651
+ template <class T, std::enable_if_t<std::is_same<T, uint16_t>::value, int> = 0>
1652
+ XSIMD_INLINE uint16x8_t x_vmaxq(uint16x8_t a, uint16x8_t b) noexcept { return vmaxq_u16(a, b); }
1653
+ template <class T, std::enable_if_t<std::is_same<T, int16_t>::value, int> = 0>
1654
+ XSIMD_INLINE int16x8_t x_vmaxq(int16x8_t a, int16x8_t b) noexcept { return vmaxq_s16(a, b); }
1655
+ template <class T, std::enable_if_t<std::is_same<T, uint32_t>::value, int> = 0>
1656
+ XSIMD_INLINE uint32x4_t x_vmaxq(uint32x4_t a, uint32x4_t b) noexcept { return vmaxq_u32(a, b); }
1657
+ template <class T, std::enable_if_t<std::is_same<T, int32_t>::value, int> = 0>
1658
+ XSIMD_INLINE int32x4_t x_vmaxq(int32x4_t a, int32x4_t b) noexcept { return vmaxq_s32(a, b); }
1659
+ template <class T, std::enable_if_t<std::is_same<T, float>::value, int> = 0>
1660
+ XSIMD_INLINE float32x4_t x_vmaxq(float32x4_t a, float32x4_t b) noexcept { return vmaxq_f32(a, b); }
1661
+ }
1662
+
1663
+ template <class A, class T, detail::exclude_int64_neon_t<T> = 0>
1664
+ XSIMD_INLINE batch<T, A> max(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon>) noexcept
1665
+ {
1666
+ using register_type = typename batch<T, A>::register_type;
1667
+ return wrap::x_vmaxq<map_to_sized_type_t<T>>(register_type(lhs), register_type(rhs));
1668
+ }
1669
+
1670
+ template <class A, class T, detail::enable_sized_integral_t<T, 8> = 0>
1671
+ XSIMD_INLINE batch<T, A> max(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon>) noexcept
1672
+ {
1673
+ return select(lhs > rhs, lhs, rhs);
1674
+ }
1675
+
1676
+ /*******
1677
+ * abs *
1678
+ *******/
1679
+
1680
+ namespace wrap
1681
+ {
1682
+ // TODO(c++17): Make a single function with if constexpr switch
1683
+ // Templating on the scalar type `T` is required because in some compilers (e.g. MSVC)
1684
+ // the vector types are all aliases of the same type.
1685
+ template <class T, std::enable_if_t<std::is_same<T, uint8_t>::value, int> = 0>
1686
+ XSIMD_INLINE uint8x16_t x_vabsq(uint8x16_t a) noexcept { return a; }
1687
+ template <class T, std::enable_if_t<std::is_same<T, int8_t>::value, int> = 0>
1688
+ XSIMD_INLINE int8x16_t x_vabsq(int8x16_t a) noexcept { return vabsq_s8(a); }
1689
+ template <class T, std::enable_if_t<std::is_same<T, uint16_t>::value, int> = 0>
1690
+ XSIMD_INLINE uint16x8_t x_vabsq(uint16x8_t a) noexcept { return a; }
1691
+ template <class T, std::enable_if_t<std::is_same<T, int16_t>::value, int> = 0>
1692
+ XSIMD_INLINE int16x8_t x_vabsq(int16x8_t a) noexcept { return vabsq_s16(a); }
1693
+ template <class T, std::enable_if_t<std::is_same<T, uint32_t>::value, int> = 0>
1694
+ XSIMD_INLINE uint32x4_t x_vabsq(uint32x4_t a) noexcept { return a; }
1695
+ template <class T, std::enable_if_t<std::is_same<T, int32_t>::value, int> = 0>
1696
+ XSIMD_INLINE int32x4_t x_vabsq(int32x4_t a) noexcept { return vabsq_s32(a); }
1697
+ template <class T, std::enable_if_t<std::is_same<T, float>::value, int> = 0>
1698
+ XSIMD_INLINE float32x4_t x_vabsq(float32x4_t a) noexcept { return vabsq_f32(a); }
1699
+ }
1700
+
1701
+ template <class A, class T, detail::exclude_int64_neon_t<T> = 0>
1702
+ XSIMD_INLINE batch<T, A> abs(batch<T, A> const& arg, requires_arch<neon>) noexcept
1703
+ {
1704
+ using register_type = typename batch<T, A>::register_type;
1705
+ return wrap::x_vabsq<map_to_sized_type_t<T>>(register_type(arg));
1706
+ }
1707
+
1708
+ /********
1709
+ * rsqrt *
1710
+ ********/
1711
+
1712
+ template <class A>
1713
+ XSIMD_INLINE batch<float, A> rsqrt(batch<float, A> const& arg, requires_arch<neon>) noexcept
1714
+ {
1715
+ return vrsqrteq_f32(arg);
1716
+ }
1717
+
1718
+ /********
1719
+ * sqrt *
1720
+ ********/
1721
+
1722
+ template <class A>
1723
+ XSIMD_INLINE batch<float, A> sqrt(batch<float, A> const& arg, requires_arch<neon>) noexcept
1724
+ {
1725
+ batch<float, A> sqrt_reciprocal = vrsqrteq_f32(arg);
1726
+ // one iter
1727
+ sqrt_reciprocal = sqrt_reciprocal * batch<float, A>(vrsqrtsq_f32(arg * sqrt_reciprocal, sqrt_reciprocal));
1728
+ batch<float, A> sqrt_approx = arg * sqrt_reciprocal * batch<float, A>(vrsqrtsq_f32(arg * sqrt_reciprocal, sqrt_reciprocal));
1729
+ batch<float, A> zero(0.f);
1730
+ return select(arg == zero, zero, sqrt_approx);
1731
+ }
1732
+
1733
+ /********************
1734
+ * Fused operations *
1735
+ ********************/
1736
+
1737
+ #ifdef __ARM_FEATURE_FMA
1738
+ template <class A>
1739
+ XSIMD_INLINE batch<float, A> fma(batch<float, A> const& x, batch<float, A> const& y, batch<float, A> const& z, requires_arch<neon>) noexcept
1740
+ {
1741
+ return vfmaq_f32(z, x, y);
1742
+ }
1743
+
1744
+ template <class A>
1745
+ XSIMD_INLINE batch<float, A> fms(batch<float, A> const& x, batch<float, A> const& y, batch<float, A> const& z, requires_arch<neon>) noexcept
1746
+ {
1747
+ return vfmaq_f32(-z, x, y);
1748
+ }
1749
+ #endif
1750
+
1751
+ /*********
1752
+ * haddp *
1753
+ *********/
1754
+
1755
+ template <class A>
1756
+ XSIMD_INLINE batch<float, A> haddp(const batch<float, A>* row, requires_arch<neon>) noexcept
1757
+ {
1758
+ // row = (a,b,c,d)
1759
+ float32x2_t tmp1, tmp2, tmp3;
1760
+ // tmp1 = (a0 + a2, a1 + a3)
1761
+ tmp1 = vpadd_f32(vget_low_f32(row[0]), vget_high_f32(row[0]));
1762
+ // tmp2 = (b0 + b2, b1 + b3)
1763
+ tmp2 = vpadd_f32(vget_low_f32(row[1]), vget_high_f32(row[1]));
1764
+ // tmp1 = (a0..3, b0..3)
1765
+ tmp1 = vpadd_f32(tmp1, tmp2);
1766
+ // tmp2 = (c0 + c2, c1 + c3)
1767
+ tmp2 = vpadd_f32(vget_low_f32(row[2]), vget_high_f32(row[2]));
1768
+ // tmp3 = (d0 + d2, d1 + d3)
1769
+ tmp3 = vpadd_f32(vget_low_f32(row[3]), vget_high_f32(row[3]));
1770
+ // tmp1 = (c0..3, d0..3)
1771
+ tmp2 = vpadd_f32(tmp2, tmp3);
1772
+ // return = (a0..3, b0..3, c0..3, d0..3)
1773
+ return vcombine_f32(tmp1, tmp2);
1774
+ }
1775
+
1776
+ /**************
1777
+ * reciprocal *
1778
+ **************/
1779
+
1780
+ template <class A>
1781
+ XSIMD_INLINE batch<float, A>
1782
+ reciprocal(const batch<float, A>& x,
1783
+ kernel::requires_arch<neon>) noexcept
1784
+ {
1785
+ return vrecpeq_f32(x);
1786
+ }
1787
+
1788
+ /**********
1789
+ * insert *
1790
+ **********/
1791
+
1792
+ template <class A, class T, size_t I, detail::enable_sized_unsigned_t<T, 1> = 0>
1793
+ XSIMD_INLINE batch<T, A> insert(batch<T, A> const& self, T val, index<I>, requires_arch<neon>) noexcept
1794
+ {
1795
+ return vsetq_lane_u8(val, self, I);
1796
+ }
1797
+
1798
+ template <class A, class T, size_t I, detail::enable_sized_signed_t<T, 1> = 0>
1799
+ XSIMD_INLINE batch<T, A> insert(batch<T, A> const& self, T val, index<I>, requires_arch<neon>) noexcept
1800
+ {
1801
+ return vsetq_lane_s8(val, self, I);
1802
+ }
1803
+
1804
+ template <class A, class T, size_t I, detail::enable_sized_unsigned_t<T, 2> = 0>
1805
+ XSIMD_INLINE batch<T, A> insert(batch<T, A> const& self, T val, index<I>, requires_arch<neon>) noexcept
1806
+ {
1807
+ return vsetq_lane_u16(val, self, I);
1808
+ }
1809
+
1810
+ template <class A, class T, size_t I, detail::enable_sized_signed_t<T, 2> = 0>
1811
+ XSIMD_INLINE batch<int16_t, A> insert(batch<int16_t, A> const& self, int16_t val, index<I>, requires_arch<neon>) noexcept
1812
+ {
1813
+ return vsetq_lane_s16(val, self, I);
1814
+ }
1815
+
1816
+ template <class A, class T, size_t I, detail::enable_sized_unsigned_t<T, 4> = 0>
1817
+ XSIMD_INLINE batch<T, A> insert(batch<T, A> const& self, T val, index<I>, requires_arch<neon>) noexcept
1818
+ {
1819
+ return vsetq_lane_u32(val, self, I);
1820
+ }
1821
+
1822
+ template <class A, class T, size_t I, detail::enable_sized_signed_t<T, 4> = 0>
1823
+ XSIMD_INLINE batch<T, A> insert(batch<T, A> const& self, T val, index<I>, requires_arch<neon>) noexcept
1824
+ {
1825
+ return vsetq_lane_s32(val, self, I);
1826
+ }
1827
+
1828
+ template <class A, class T, size_t I, detail::enable_sized_unsigned_t<T, 8> = 0>
1829
+ XSIMD_INLINE batch<T, A> insert(batch<T, A> const& self, T val, index<I>, requires_arch<neon>) noexcept
1830
+ {
1831
+ return vsetq_lane_u64(val, self, I);
1832
+ }
1833
+
1834
+ template <class A, class T, size_t I, detail::enable_sized_signed_t<T, 8> = 0>
1835
+ XSIMD_INLINE batch<T, A> insert(batch<T, A> const& self, T val, index<I>, requires_arch<neon>) noexcept
1836
+ {
1837
+ return vsetq_lane_s64(val, self, I);
1838
+ }
1839
+
1840
+ template <class A, size_t I>
1841
+ XSIMD_INLINE batch<float, A> insert(batch<float, A> const& self, float val, index<I>, requires_arch<neon>) noexcept
1842
+ {
1843
+ return vsetq_lane_f32(val, self, I);
1844
+ }
1845
+
1846
+ /********************
1847
+ * nearbyint_as_int *
1848
+ *******************/
1849
+
1850
+ template <class A>
1851
+ XSIMD_INLINE batch<int32_t, A> nearbyint_as_int(batch<float, A> const& self,
1852
+ requires_arch<neon>) noexcept
1853
+ {
1854
+ /* origin: https://github.com/DLTcollab/sse2neon/blob/cad518a93b326f0f644b7972d488d04eaa2b0475/sse2neon.h#L4028-L4047 */
1855
+ // Contributors to this work are:
1856
+ // John W. Ratcliff <jratcliffscarab@gmail.com>
1857
+ // Brandon Rowlett <browlett@nvidia.com>
1858
+ // Ken Fast <kfast@gdeb.com>
1859
+ // Eric van Beurden <evanbeurden@nvidia.com>
1860
+ // Alexander Potylitsin <apotylitsin@nvidia.com>
1861
+ // Hasindu Gamaarachchi <hasindu2008@gmail.com>
1862
+ // Jim Huang <jserv@biilabs.io>
1863
+ // Mark Cheng <marktwtn@biilabs.io>
1864
+ // Malcolm James MacLeod <malcolm@gulden.com>
1865
+ // Devin Hussey (easyaspi314) <husseydevin@gmail.com>
1866
+ // Sebastian Pop <spop@amazon.com>
1867
+ // Developer Ecosystem Engineering <DeveloperEcosystemEngineering@apple.com>
1868
+ // Danila Kutenin <danilak@google.com>
1869
+ // François Turban (JishinMaster) <francois.turban@gmail.com>
1870
+ // Pei-Hsuan Hung <afcidk@gmail.com>
1871
+ // Yang-Hao Yuan <yanghau@biilabs.io>
1872
+ // Syoyo Fujita <syoyo@lighttransport.com>
1873
+ // Brecht Van Lommel <brecht@blender.org>
1874
+
1875
+ /*
1876
+ * sse2neon is freely redistributable under the MIT License.
1877
+ *
1878
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
1879
+ * of this software and associated documentation files (the "Software"), to deal
1880
+ * in the Software without restriction, including without limitation the rights
1881
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1882
+ * copies of the Software, and to permit persons to whom the Software is
1883
+ * furnished to do so, subject to the following conditions:
1884
+ *
1885
+ * The above copyright notice and this permission notice shall be included in
1886
+ * all copies or substantial portions of the Software.
1887
+ *
1888
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1889
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1890
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1891
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1892
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
1893
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
1894
+ * SOFTWARE.
1895
+ */
1896
+
1897
+ const auto signmask = vdupq_n_u32(0x80000000);
1898
+ const auto half = vbslq_f32(signmask, self,
1899
+ vdupq_n_f32(0.5f)); /* +/- 0.5 */
1900
+ const auto r_normal = vcvtq_s32_f32(vaddq_f32(
1901
+ self, half)); /* round to integer: [a + 0.5]*/
1902
+ const auto r_trunc = vcvtq_s32_f32(self); /* truncate to integer: [a] */
1903
+ const auto plusone = vreinterpretq_s32_u32(vshrq_n_u32(
1904
+ vreinterpretq_u32_s32(vnegq_s32(r_trunc)), 31)); /* 1 or 0 */
1905
+ const auto r_even = vbicq_s32(vaddq_s32(r_trunc, plusone),
1906
+ vdupq_n_s32(1)); /* ([a] + {0,1}) & ~1 */
1907
+ const auto delta = vsubq_f32(
1908
+ self,
1909
+ vcvtq_f32_s32(r_trunc)); /* compute delta: delta = (a - [a]) */
1910
+ const auto is_delta_half = vceqq_f32(delta, half); /* delta == +/- 0.5 */
1911
+ return vbslq_s32(is_delta_half, r_even, r_normal);
1912
+ }
1913
+
1914
+ /**************
1915
+ * reduce_add *
1916
+ **************/
1917
+
1918
+ namespace detail
1919
+ {
1920
+ template <class T, class A, class V>
1921
+ XSIMD_INLINE T sum_batch(V const& arg) noexcept
1922
+ {
1923
+ T res = T(0);
1924
+ for (std::size_t i = 0; i < batch<T, A>::size; ++i)
1925
+ {
1926
+ res += arg[i];
1927
+ }
1928
+ return res;
1929
+ }
1930
+ }
1931
+
1932
+ template <class A, class T, detail::enable_sized_unsigned_t<T, 1> = 0>
1933
+ XSIMD_INLINE typename batch<T, A>::value_type reduce_add(batch<T, A> const& arg, requires_arch<neon>) noexcept
1934
+ {
1935
+ uint8x8_t tmp = vpadd_u8(vget_low_u8(arg), vget_high_u8(arg));
1936
+ tmp = vpadd_u8(tmp, tmp);
1937
+ tmp = vpadd_u8(tmp, tmp);
1938
+ tmp = vpadd_u8(tmp, tmp);
1939
+ return vget_lane_u8(tmp, 0);
1940
+ }
1941
+
1942
+ template <class A, class T, detail::enable_sized_signed_t<T, 1> = 0>
1943
+ XSIMD_INLINE typename batch<T, A>::value_type reduce_add(batch<T, A> const& arg, requires_arch<neon>) noexcept
1944
+ {
1945
+ int8x8_t tmp = vpadd_s8(vget_low_s8(arg), vget_high_s8(arg));
1946
+ tmp = vpadd_s8(tmp, tmp);
1947
+ tmp = vpadd_s8(tmp, tmp);
1948
+ tmp = vpadd_s8(tmp, tmp);
1949
+ return vget_lane_s8(tmp, 0);
1950
+ }
1951
+
1952
+ template <class A, class T, detail::enable_sized_unsigned_t<T, 2> = 0>
1953
+ XSIMD_INLINE typename batch<T, A>::value_type reduce_add(batch<T, A> const& arg, requires_arch<neon>) noexcept
1954
+ {
1955
+ uint16x4_t tmp = vpadd_u16(vget_low_u16(arg), vget_high_u16(arg));
1956
+ tmp = vpadd_u16(tmp, tmp);
1957
+ tmp = vpadd_u16(tmp, tmp);
1958
+ return vget_lane_u16(tmp, 0);
1959
+ }
1960
+
1961
+ template <class A, class T, detail::enable_sized_signed_t<T, 2> = 0>
1962
+ XSIMD_INLINE typename batch<T, A>::value_type reduce_add(batch<T, A> const& arg, requires_arch<neon>) noexcept
1963
+ {
1964
+ int16x4_t tmp = vpadd_s16(vget_low_s16(arg), vget_high_s16(arg));
1965
+ tmp = vpadd_s16(tmp, tmp);
1966
+ tmp = vpadd_s16(tmp, tmp);
1967
+ return vget_lane_s16(tmp, 0);
1968
+ }
1969
+
1970
+ template <class A, class T, detail::enable_sized_unsigned_t<T, 4> = 0>
1971
+ XSIMD_INLINE typename batch<T, A>::value_type reduce_add(batch<T, A> const& arg, requires_arch<neon>) noexcept
1972
+ {
1973
+ uint32x2_t tmp = vpadd_u32(vget_low_u32(arg), vget_high_u32(arg));
1974
+ tmp = vpadd_u32(tmp, tmp);
1975
+ return vget_lane_u32(tmp, 0);
1976
+ }
1977
+
1978
+ template <class A, class T, detail::enable_sized_signed_t<T, 4> = 0>
1979
+ XSIMD_INLINE typename batch<T, A>::value_type reduce_add(batch<T, A> const& arg, requires_arch<neon>) noexcept
1980
+ {
1981
+ int32x2_t tmp = vpadd_s32(vget_low_s32(arg), vget_high_s32(arg));
1982
+ tmp = vpadd_s32(tmp, tmp);
1983
+ return vget_lane_s32(tmp, 0);
1984
+ }
1985
+
1986
+ template <class A, class T, detail::enable_sized_integral_t<T, 8> = 0>
1987
+ XSIMD_INLINE typename batch<T, A>::value_type reduce_add(batch<T, A> const& arg, requires_arch<neon>) noexcept
1988
+ {
1989
+ return arg.get(0) + arg.get(1);
1990
+ }
1991
+
1992
+ template <class A>
1993
+ XSIMD_INLINE float reduce_add(batch<float, A> const& arg, requires_arch<neon>) noexcept
1994
+ {
1995
+ float32x2_t tmp = vpadd_f32(vget_low_f32(arg), vget_high_f32(arg));
1996
+ tmp = vpadd_f32(tmp, tmp);
1997
+ return vget_lane_f32(tmp, 0);
1998
+ }
1999
+
2000
+ /**************
2001
+ * reduce_max *
2002
+ **************/
2003
+
2004
+ // Using common implementation because ARM does not provide intrinsics
2005
+ // for this operation
2006
+
2007
+ /**************
2008
+ * reduce_min *
2009
+ **************/
2010
+
2011
+ // Using common implementation because ARM does not provide intrinsics
2012
+ // for this operation
2013
+
2014
+ /**************
2015
+ * reduce_mul *
2016
+ **************/
2017
+
2018
+ // Using common implementation because ARM does not provide intrinsics
2019
+ // for this operation
2020
+
2021
+ /**********
2022
+ * select *
2023
+ **********/
2024
+
2025
+ namespace wrap
2026
+ {
2027
+ // TODO(c++17): Make a single function with if constexpr switch
2028
+ // Templating on the scalar type `T` is required because in some compilers (e.g. MSVC)
2029
+ // the vector types are all aliases of the same type.
2030
+ template <class T, std::enable_if_t<std::is_same<T, uint8_t>::value, int> = 0>
2031
+ XSIMD_INLINE uint8x16_t x_vbslq(uint8x16_t a, uint8x16_t b, uint8x16_t c) noexcept { return vbslq_u8(a, b, c); }
2032
+ template <class T, std::enable_if_t<std::is_same<T, int8_t>::value, int> = 0>
2033
+ XSIMD_INLINE int8x16_t x_vbslq(uint8x16_t a, int8x16_t b, int8x16_t c) noexcept { return vbslq_s8(a, b, c); }
2034
+ template <class T, std::enable_if_t<std::is_same<T, uint16_t>::value, int> = 0>
2035
+ XSIMD_INLINE uint16x8_t x_vbslq(uint16x8_t a, uint16x8_t b, uint16x8_t c) noexcept { return vbslq_u16(a, b, c); }
2036
+ template <class T, std::enable_if_t<std::is_same<T, int16_t>::value, int> = 0>
2037
+ XSIMD_INLINE int16x8_t x_vbslq(uint16x8_t a, int16x8_t b, int16x8_t c) noexcept { return vbslq_s16(a, b, c); }
2038
+ template <class T, std::enable_if_t<std::is_same<T, uint32_t>::value, int> = 0>
2039
+ XSIMD_INLINE uint32x4_t x_vbslq(uint32x4_t a, uint32x4_t b, uint32x4_t c) noexcept { return vbslq_u32(a, b, c); }
2040
+ template <class T, std::enable_if_t<std::is_same<T, int32_t>::value, int> = 0>
2041
+ XSIMD_INLINE int32x4_t x_vbslq(uint32x4_t a, int32x4_t b, int32x4_t c) noexcept { return vbslq_s32(a, b, c); }
2042
+ template <class T, std::enable_if_t<std::is_same<T, uint64_t>::value, int> = 0>
2043
+ XSIMD_INLINE uint64x2_t x_vbslq(uint64x2_t a, uint64x2_t b, uint64x2_t c) noexcept { return vbslq_u64(a, b, c); }
2044
+ template <class T, std::enable_if_t<std::is_same<T, int64_t>::value, int> = 0>
2045
+ XSIMD_INLINE int64x2_t x_vbslq(uint64x2_t a, int64x2_t b, int64x2_t c) noexcept { return vbslq_s64(a, b, c); }
2046
+ template <class T, std::enable_if_t<std::is_same<T, float>::value, int> = 0>
2047
+ XSIMD_INLINE float32x4_t x_vbslq(uint32x4_t a, float32x4_t b, float32x4_t c) noexcept { return vbslq_f32(a, b, c); }
2048
+ }
2049
+
2050
+ template <class A, class T, detail::enable_neon_type_t<T> = 0>
2051
+ XSIMD_INLINE batch<T, A> select(batch_bool<T, A> const& cond, batch<T, A> const& a, batch<T, A> const& b, requires_arch<neon>) noexcept
2052
+ {
2053
+ using bool_register_type = typename batch_bool<T, A>::register_type;
2054
+ using register_type = typename batch<T, A>::register_type;
2055
+ return wrap::x_vbslq<map_to_sized_type_t<T>>(bool_register_type(cond), register_type(a), register_type(b));
2056
+ }
2057
+
2058
+ template <class A, class T, bool... b, detail::enable_neon_type_t<T> = 0>
2059
+ XSIMD_INLINE batch<T, A> select(batch_bool_constant<T, A, b...> const&, batch<T, A> const& true_br, batch<T, A> const& false_br, requires_arch<neon>) noexcept
2060
+ {
2061
+ return select(batch_bool<T, A> { b... }, true_br, false_br, neon {});
2062
+ }
2063
+
2064
+ /*************
2065
+ * transpose *
2066
+ *************/
2067
+ template <class A>
2068
+ XSIMD_INLINE void transpose(batch<float, A>* matrix_begin, batch<float, A>* matrix_end, requires_arch<neon>) noexcept
2069
+ {
2070
+ assert((matrix_end - matrix_begin == batch<float, A>::size) && "correctly sized matrix");
2071
+ (void)matrix_end;
2072
+ auto r0 = matrix_begin[0], r1 = matrix_begin[1], r2 = matrix_begin[2], r3 = matrix_begin[3];
2073
+ auto t01 = vtrnq_f32(r0, r1);
2074
+ auto t23 = vtrnq_f32(r2, r3);
2075
+ matrix_begin[0] = vcombine_f32(vget_low_f32(t01.val[0]), vget_low_f32(t23.val[0]));
2076
+ matrix_begin[1] = vcombine_f32(vget_low_f32(t01.val[1]), vget_low_f32(t23.val[1]));
2077
+ matrix_begin[2] = vcombine_f32(vget_high_f32(t01.val[0]), vget_high_f32(t23.val[0]));
2078
+ matrix_begin[3] = vcombine_f32(vget_high_f32(t01.val[1]), vget_high_f32(t23.val[1]));
2079
+ }
2080
+ template <class A>
2081
+ XSIMD_INLINE void transpose(batch<uint32_t, A>* matrix_begin, batch<uint32_t, A>* matrix_end, requires_arch<neon>) noexcept
2082
+ {
2083
+ assert((matrix_end - matrix_begin == batch<uint32_t, A>::size) && "correctly sized matrix");
2084
+ (void)matrix_end;
2085
+ auto r0 = matrix_begin[0], r1 = matrix_begin[1], r2 = matrix_begin[2], r3 = matrix_begin[3];
2086
+ auto t01 = vtrnq_u32(r0, r1);
2087
+ auto t23 = vtrnq_u32(r2, r3);
2088
+ matrix_begin[0] = vcombine_u32(vget_low_u32(t01.val[0]), vget_low_u32(t23.val[0]));
2089
+ matrix_begin[1] = vcombine_u32(vget_low_u32(t01.val[1]), vget_low_u32(t23.val[1]));
2090
+ matrix_begin[2] = vcombine_u32(vget_high_u32(t01.val[0]), vget_high_u32(t23.val[0]));
2091
+ matrix_begin[3] = vcombine_u32(vget_high_u32(t01.val[1]), vget_high_u32(t23.val[1]));
2092
+ }
2093
+ template <class A>
2094
+ XSIMD_INLINE void transpose(batch<int32_t, A>* matrix_begin, batch<int32_t, A>* matrix_end, requires_arch<neon>) noexcept
2095
+ {
2096
+ assert((matrix_end - matrix_begin == batch<int32_t, A>::size) && "correctly sized matrix");
2097
+ (void)matrix_end;
2098
+ auto r0 = matrix_begin[0], r1 = matrix_begin[1], r2 = matrix_begin[2], r3 = matrix_begin[3];
2099
+ auto t01 = vtrnq_s32(r0, r1);
2100
+ auto t23 = vtrnq_s32(r2, r3);
2101
+ matrix_begin[0] = vcombine_s32(vget_low_s32(t01.val[0]), vget_low_s32(t23.val[0]));
2102
+ matrix_begin[1] = vcombine_s32(vget_low_s32(t01.val[1]), vget_low_s32(t23.val[1]));
2103
+ matrix_begin[2] = vcombine_s32(vget_high_s32(t01.val[0]), vget_high_s32(t23.val[0]));
2104
+ matrix_begin[3] = vcombine_s32(vget_high_s32(t01.val[1]), vget_high_s32(t23.val[1]));
2105
+ }
2106
+
2107
+ template <class A, class T, detail::enable_sized_unsigned_t<T, 8> = 0>
2108
+ XSIMD_INLINE void transpose(batch<T, A>* matrix_begin, batch<T, A>* matrix_end, requires_arch<neon>) noexcept
2109
+ {
2110
+ assert((matrix_end - matrix_begin == batch<T, A>::size) && "correctly sized matrix");
2111
+ (void)matrix_end;
2112
+ auto r0 = matrix_begin[0], r1 = matrix_begin[1];
2113
+ matrix_begin[0] = vcombine_u64(vget_low_u64(r0), vget_low_u64(r1));
2114
+ matrix_begin[1] = vcombine_u64(vget_high_u64(r0), vget_high_u64(r1));
2115
+ }
2116
+
2117
+ template <class A, class T, detail::enable_sized_signed_t<T, 8> = 0>
2118
+ XSIMD_INLINE void transpose(batch<T, A>* matrix_begin, batch<T, A>* matrix_end, requires_arch<neon>) noexcept
2119
+ {
2120
+ assert((matrix_end - matrix_begin == batch<T, A>::size) && "correctly sized matrix");
2121
+ (void)matrix_end;
2122
+ auto r0 = matrix_begin[0], r1 = matrix_begin[1];
2123
+ matrix_begin[0] = vcombine_s64(vget_low_s64(r0), vget_low_s64(r1));
2124
+ matrix_begin[1] = vcombine_s64(vget_high_s64(r0), vget_high_s64(r1));
2125
+ }
2126
+
2127
+ /**********
2128
+ * zip_lo *
2129
+ **********/
2130
+
2131
+ template <class A, class T, detail::enable_sized_unsigned_t<T, 1> = 0>
2132
+ XSIMD_INLINE batch<T, A> zip_lo(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon>) noexcept
2133
+ {
2134
+ uint8x8x2_t tmp = vzip_u8(vget_low_u8(lhs), vget_low_u8(rhs));
2135
+ return vcombine_u8(tmp.val[0], tmp.val[1]);
2136
+ }
2137
+
2138
+ template <class A, class T, detail::enable_sized_signed_t<T, 1> = 0>
2139
+ XSIMD_INLINE batch<T, A> zip_lo(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon>) noexcept
2140
+ {
2141
+ int8x8x2_t tmp = vzip_s8(vget_low_s8(lhs), vget_low_s8(rhs));
2142
+ return vcombine_s8(tmp.val[0], tmp.val[1]);
2143
+ }
2144
+
2145
+ template <class A, class T, detail::enable_sized_unsigned_t<T, 2> = 0>
2146
+ XSIMD_INLINE batch<T, A> zip_lo(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon>) noexcept
2147
+ {
2148
+ uint16x4x2_t tmp = vzip_u16(vget_low_u16(lhs), vget_low_u16(rhs));
2149
+ return vcombine_u16(tmp.val[0], tmp.val[1]);
2150
+ }
2151
+
2152
+ template <class A, class T, detail::enable_sized_signed_t<T, 2> = 0>
2153
+ XSIMD_INLINE batch<T, A> zip_lo(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon>) noexcept
2154
+ {
2155
+ int16x4x2_t tmp = vzip_s16(vget_low_s16(lhs), vget_low_s16(rhs));
2156
+ return vcombine_s16(tmp.val[0], tmp.val[1]);
2157
+ }
2158
+
2159
+ template <class A, class T, detail::enable_sized_unsigned_t<T, 4> = 0>
2160
+ XSIMD_INLINE batch<T, A> zip_lo(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon>) noexcept
2161
+ {
2162
+ uint32x2x2_t tmp = vzip_u32(vget_low_u32(lhs), vget_low_u32(rhs));
2163
+ return vcombine_u32(tmp.val[0], tmp.val[1]);
2164
+ }
2165
+
2166
+ template <class A, class T, detail::enable_sized_signed_t<T, 4> = 0>
2167
+ XSIMD_INLINE batch<T, A> zip_lo(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon>) noexcept
2168
+ {
2169
+ int32x2x2_t tmp = vzip_s32(vget_low_s32(lhs), vget_low_s32(rhs));
2170
+ return vcombine_s32(tmp.val[0], tmp.val[1]);
2171
+ }
2172
+
2173
+ template <class A, class T, detail::enable_sized_unsigned_t<T, 8> = 0>
2174
+ XSIMD_INLINE batch<T, A> zip_lo(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon>) noexcept
2175
+ {
2176
+ return vcombine_u64(vget_low_u64(lhs), vget_low_u64(rhs));
2177
+ }
2178
+
2179
+ template <class A, class T, detail::enable_sized_signed_t<T, 8> = 0>
2180
+ XSIMD_INLINE batch<T, A> zip_lo(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon>) noexcept
2181
+ {
2182
+ return vcombine_s64(vget_low_s64(lhs), vget_low_s64(rhs));
2183
+ }
2184
+
2185
+ template <class A>
2186
+ XSIMD_INLINE batch<float, A> zip_lo(batch<float, A> const& lhs, batch<float, A> const& rhs, requires_arch<neon>) noexcept
2187
+ {
2188
+ float32x2x2_t tmp = vzip_f32(vget_low_f32(lhs), vget_low_f32(rhs));
2189
+ return vcombine_f32(tmp.val[0], tmp.val[1]);
2190
+ }
2191
+
2192
+ /**********
2193
+ * zip_hi *
2194
+ **********/
2195
+
2196
+ template <class A, class T, detail::enable_sized_unsigned_t<T, 1> = 0>
2197
+ XSIMD_INLINE batch<T, A> zip_hi(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon>) noexcept
2198
+ {
2199
+ uint8x8x2_t tmp = vzip_u8(vget_high_u8(lhs), vget_high_u8(rhs));
2200
+ return vcombine_u8(tmp.val[0], tmp.val[1]);
2201
+ }
2202
+
2203
+ template <class A, class T, detail::enable_sized_signed_t<T, 1> = 0>
2204
+ XSIMD_INLINE batch<T, A> zip_hi(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon>) noexcept
2205
+ {
2206
+ int8x8x2_t tmp = vzip_s8(vget_high_s8(lhs), vget_high_s8(rhs));
2207
+ return vcombine_s8(tmp.val[0], tmp.val[1]);
2208
+ }
2209
+
2210
+ template <class A, class T, detail::enable_sized_unsigned_t<T, 2> = 0>
2211
+ XSIMD_INLINE batch<T, A> zip_hi(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon>) noexcept
2212
+ {
2213
+ uint16x4x2_t tmp = vzip_u16(vget_high_u16(lhs), vget_high_u16(rhs));
2214
+ return vcombine_u16(tmp.val[0], tmp.val[1]);
2215
+ }
2216
+
2217
+ template <class A, class T, detail::enable_sized_signed_t<T, 2> = 0>
2218
+ XSIMD_INLINE batch<T, A> zip_hi(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon>) noexcept
2219
+ {
2220
+ int16x4x2_t tmp = vzip_s16(vget_high_s16(lhs), vget_high_s16(rhs));
2221
+ return vcombine_s16(tmp.val[0], tmp.val[1]);
2222
+ }
2223
+
2224
+ template <class A, class T, detail::enable_sized_unsigned_t<T, 4> = 0>
2225
+ XSIMD_INLINE batch<T, A> zip_hi(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon>) noexcept
2226
+ {
2227
+ uint32x2x2_t tmp = vzip_u32(vget_high_u32(lhs), vget_high_u32(rhs));
2228
+ return vcombine_u32(tmp.val[0], tmp.val[1]);
2229
+ }
2230
+
2231
+ template <class A, class T, detail::enable_sized_signed_t<T, 4> = 0>
2232
+ XSIMD_INLINE batch<T, A> zip_hi(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon>) noexcept
2233
+ {
2234
+ int32x2x2_t tmp = vzip_s32(vget_high_s32(lhs), vget_high_s32(rhs));
2235
+ return vcombine_s32(tmp.val[0], tmp.val[1]);
2236
+ }
2237
+
2238
+ template <class A, class T, detail::enable_sized_unsigned_t<T, 8> = 0>
2239
+ XSIMD_INLINE batch<T, A> zip_hi(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon>) noexcept
2240
+ {
2241
+ return vcombine_u64(vget_high_u64(lhs), vget_high_u64(rhs));
2242
+ }
2243
+
2244
+ template <class A, class T, detail::enable_sized_signed_t<T, 8> = 0>
2245
+ XSIMD_INLINE batch<T, A> zip_hi(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon>) noexcept
2246
+ {
2247
+ return vcombine_s64(vget_high_s64(lhs), vget_high_s64(rhs));
2248
+ }
2249
+
2250
+ template <class A>
2251
+ XSIMD_INLINE batch<float, A> zip_hi(batch<float, A> const& lhs, batch<float, A> const& rhs, requires_arch<neon>) noexcept
2252
+ {
2253
+ float32x2x2_t tmp = vzip_f32(vget_high_f32(lhs), vget_high_f32(rhs));
2254
+ return vcombine_f32(tmp.val[0], tmp.val[1]);
2255
+ }
2256
+
2257
+ /****************
2258
+ * extract_pair *
2259
+ ****************/
2260
+
2261
+ namespace detail
2262
+ {
2263
+ template <class A, class T>
2264
+ XSIMD_INLINE batch<T, A> extract_pair(batch<T, A> const&, batch<T, A> const& /*rhs*/, std::size_t, std::index_sequence<>) noexcept
2265
+ {
2266
+ assert(false && "extract_pair out of bounds");
2267
+ return batch<T, A> {};
2268
+ }
2269
+
2270
+ template <class A, class T, size_t I, size_t... Is, detail::enable_sized_unsigned_t<T, 1> = 0>
2271
+ XSIMD_INLINE batch<T, A> extract_pair(batch<T, A> const& lhs, batch<T, A> const& rhs, std::size_t n, std::index_sequence<I, Is...>) noexcept
2272
+ {
2273
+ if (n == I)
2274
+ {
2275
+ return vextq_u8(rhs, lhs, I);
2276
+ }
2277
+ else
2278
+ {
2279
+ return extract_pair(lhs, rhs, n, std::index_sequence<Is...>());
2280
+ }
2281
+ }
2282
+
2283
+ template <class A, class T, size_t I, size_t... Is, detail::enable_sized_signed_t<T, 1> = 0>
2284
+ XSIMD_INLINE batch<T, A> extract_pair(batch<T, A> const& lhs, batch<T, A> const& rhs, std::size_t n, std::index_sequence<I, Is...>) noexcept
2285
+ {
2286
+ if (n == I)
2287
+ {
2288
+ return vextq_s8(rhs, lhs, I);
2289
+ }
2290
+ else
2291
+ {
2292
+ return extract_pair(lhs, rhs, n, std::index_sequence<Is...>());
2293
+ }
2294
+ }
2295
+
2296
+ template <class A, class T, size_t I, size_t... Is, detail::enable_sized_unsigned_t<T, 2> = 0>
2297
+ XSIMD_INLINE batch<T, A> extract_pair(batch<T, A> const& lhs, batch<T, A> const& rhs, std::size_t n, std::index_sequence<I, Is...>) noexcept
2298
+ {
2299
+ if (n == I)
2300
+ {
2301
+ return vextq_u16(rhs, lhs, I);
2302
+ }
2303
+ else
2304
+ {
2305
+ return extract_pair(lhs, rhs, n, std::index_sequence<Is...>());
2306
+ }
2307
+ }
2308
+
2309
+ template <class A, class T, size_t I, size_t... Is, detail::enable_sized_signed_t<T, 2> = 0>
2310
+ XSIMD_INLINE batch<T, A> extract_pair(batch<T, A> const& lhs, batch<T, A> const& rhs, std::size_t n, std::index_sequence<I, Is...>) noexcept
2311
+ {
2312
+ if (n == I)
2313
+ {
2314
+ return vextq_s16(rhs, lhs, I);
2315
+ }
2316
+ else
2317
+ {
2318
+ return extract_pair(lhs, rhs, n, std::index_sequence<Is...>());
2319
+ }
2320
+ }
2321
+
2322
+ template <class A, class T, size_t I, size_t... Is, detail::enable_sized_unsigned_t<T, 4> = 0>
2323
+ XSIMD_INLINE batch<T, A> extract_pair(batch<T, A> const& lhs, batch<T, A> const& rhs, std::size_t n, std::index_sequence<I, Is...>) noexcept
2324
+ {
2325
+ if (n == I)
2326
+ {
2327
+ return vextq_u32(rhs, lhs, I);
2328
+ }
2329
+ else
2330
+ {
2331
+ return extract_pair(lhs, rhs, n, std::index_sequence<Is...>());
2332
+ }
2333
+ }
2334
+
2335
+ template <class A, class T, size_t I, size_t... Is, detail::enable_sized_signed_t<T, 4> = 0>
2336
+ XSIMD_INLINE batch<T, A> extract_pair(batch<T, A> const& lhs, batch<T, A> const& rhs, std::size_t n, std::index_sequence<I, Is...>) noexcept
2337
+ {
2338
+ if (n == I)
2339
+ {
2340
+ return vextq_s32(rhs, lhs, I);
2341
+ }
2342
+ else
2343
+ {
2344
+ return extract_pair(lhs, rhs, n, std::index_sequence<Is...>());
2345
+ }
2346
+ }
2347
+
2348
+ template <class A, class T, size_t I, size_t... Is, detail::enable_sized_unsigned_t<T, 8> = 0>
2349
+ XSIMD_INLINE batch<T, A> extract_pair(batch<T, A> const& lhs, batch<T, A> const& rhs, std::size_t n, std::index_sequence<I, Is...>) noexcept
2350
+ {
2351
+ if (n == I)
2352
+ {
2353
+ return vextq_u64(rhs, lhs, I);
2354
+ }
2355
+ else
2356
+ {
2357
+ return extract_pair(lhs, rhs, n, std::index_sequence<Is...>());
2358
+ }
2359
+ }
2360
+
2361
+ template <class A, class T, size_t I, size_t... Is, detail::enable_sized_signed_t<T, 8> = 0>
2362
+ XSIMD_INLINE batch<T, A> extract_pair(batch<T, A> const& lhs, batch<T, A> const& rhs, std::size_t n, std::index_sequence<I, Is...>) noexcept
2363
+ {
2364
+ if (n == I)
2365
+ {
2366
+ return vextq_s64(rhs, lhs, I);
2367
+ }
2368
+ else
2369
+ {
2370
+ return extract_pair(lhs, rhs, n, std::index_sequence<Is...>());
2371
+ }
2372
+ }
2373
+
2374
+ template <class A, size_t I, size_t... Is>
2375
+ XSIMD_INLINE batch<float, A> extract_pair(batch<float, A> const& lhs, batch<float, A> const& rhs, std::size_t n, std::index_sequence<I, Is...>) noexcept
2376
+ {
2377
+ if (n == I)
2378
+ {
2379
+ return vextq_f32(rhs, lhs, I);
2380
+ }
2381
+ else
2382
+ {
2383
+ return extract_pair(lhs, rhs, n, std::index_sequence<Is...>());
2384
+ }
2385
+ }
2386
+
2387
+ template <class A, class T, size_t... Is>
2388
+ XSIMD_INLINE batch<T, A> extract_pair_impl(batch<T, A> const& lhs, batch<T, A> const& rhs, std::size_t n, std::index_sequence<0, Is...>) noexcept
2389
+ {
2390
+ if (n == 0)
2391
+ {
2392
+ return rhs;
2393
+ }
2394
+ else
2395
+ {
2396
+ return extract_pair(lhs, rhs, n, std::index_sequence<Is...>());
2397
+ }
2398
+ }
2399
+ }
2400
+
2401
+ template <class A, class T>
2402
+ XSIMD_INLINE batch<T, A> extract_pair(batch<T, A> const& lhs, batch<T, A> const& rhs, std::size_t n, requires_arch<neon>) noexcept
2403
+ {
2404
+ constexpr std::size_t size = batch<T, A>::size;
2405
+ assert(n < size && "index in bounds");
2406
+ return detail::extract_pair_impl(lhs, rhs, n, std::make_index_sequence<size>());
2407
+ }
2408
+
2409
+ /******************
2410
+ * bitwise_lshift *
2411
+ ******************/
2412
+
2413
+ namespace detail
2414
+ {
2415
+ template <class A, class T>
2416
+ XSIMD_INLINE batch<T, A> bitwise_lshift(batch<T, A> const& /*lhs*/, int /*n*/, ::xsimd::detail::int_sequence<>) noexcept
2417
+ {
2418
+ assert(false && "bitwise_lshift out of bounds");
2419
+ return batch<T, A> {};
2420
+ }
2421
+
2422
+ template <class A, class T, int I, int... Is, detail::enable_sized_unsigned_t<T, 1> = 0>
2423
+ XSIMD_INLINE batch<T, A> bitwise_lshift(batch<T, A> const& lhs, int n, ::xsimd::detail::int_sequence<I, Is...>) noexcept
2424
+ {
2425
+ if (n == I)
2426
+ {
2427
+ return vshlq_n_u8(lhs, I);
2428
+ }
2429
+ else
2430
+ {
2431
+ return bitwise_lshift(lhs, n, ::xsimd::detail::int_sequence<Is...>());
2432
+ }
2433
+ }
2434
+
2435
+ template <class A, class T, int I, int... Is, detail::enable_sized_signed_t<T, 1> = 0>
2436
+ XSIMD_INLINE batch<T, A> bitwise_lshift(batch<T, A> const& lhs, int n, ::xsimd::detail::int_sequence<I, Is...>) noexcept
2437
+ {
2438
+ if (n == I)
2439
+ {
2440
+ return vshlq_n_s8(lhs, I);
2441
+ }
2442
+ else
2443
+ {
2444
+ return bitwise_lshift(lhs, n, ::xsimd::detail::int_sequence<Is...>());
2445
+ }
2446
+ }
2447
+
2448
+ template <class A, class T, int I, int... Is, detail::enable_sized_unsigned_t<T, 2> = 0>
2449
+ XSIMD_INLINE batch<T, A> bitwise_lshift(batch<T, A> const& lhs, int n, ::xsimd::detail::int_sequence<I, Is...>) noexcept
2450
+ {
2451
+ if (n == I)
2452
+ {
2453
+ return vshlq_n_u16(lhs, I);
2454
+ }
2455
+ else
2456
+ {
2457
+ return bitwise_lshift(lhs, n, ::xsimd::detail::int_sequence<Is...>());
2458
+ }
2459
+ }
2460
+
2461
+ template <class A, class T, int I, int... Is, detail::enable_sized_signed_t<T, 2> = 0>
2462
+ XSIMD_INLINE batch<T, A> bitwise_lshift(batch<T, A> const& lhs, int n, ::xsimd::detail::int_sequence<I, Is...>) noexcept
2463
+ {
2464
+ if (n == I)
2465
+ {
2466
+ return vshlq_n_s16(lhs, I);
2467
+ }
2468
+ else
2469
+ {
2470
+ return bitwise_lshift(lhs, n, ::xsimd::detail::int_sequence<Is...>());
2471
+ }
2472
+ }
2473
+
2474
+ template <class A, class T, int I, int... Is, detail::enable_sized_unsigned_t<T, 4> = 0>
2475
+ XSIMD_INLINE batch<T, A> bitwise_lshift(batch<T, A> const& lhs, int n, ::xsimd::detail::int_sequence<I, Is...>) noexcept
2476
+ {
2477
+ if (n == I)
2478
+ {
2479
+ return vshlq_n_u32(lhs, I);
2480
+ }
2481
+ else
2482
+ {
2483
+ return bitwise_lshift(lhs, n, ::xsimd::detail::int_sequence<Is...>());
2484
+ }
2485
+ }
2486
+
2487
+ template <class A, class T, int I, int... Is, detail::enable_sized_signed_t<T, 4> = 0>
2488
+ XSIMD_INLINE batch<T, A> bitwise_lshift(batch<T, A> const& lhs, int n, ::xsimd::detail::int_sequence<I, Is...>) noexcept
2489
+ {
2490
+ if (n == I)
2491
+ {
2492
+ return vshlq_n_s32(lhs, I);
2493
+ }
2494
+ else
2495
+ {
2496
+ return bitwise_lshift(lhs, n, ::xsimd::detail::int_sequence<Is...>());
2497
+ }
2498
+ }
2499
+
2500
+ template <class A, class T, int I, int... Is, detail::enable_sized_unsigned_t<T, 8> = 0>
2501
+ XSIMD_INLINE batch<T, A> bitwise_lshift(batch<T, A> const& lhs, int n, ::xsimd::detail::int_sequence<I, Is...>) noexcept
2502
+ {
2503
+ if (n == I)
2504
+ {
2505
+ return vshlq_n_u64(lhs, I);
2506
+ }
2507
+ else
2508
+ {
2509
+ return bitwise_lshift(lhs, n, ::xsimd::detail::int_sequence<Is...>());
2510
+ }
2511
+ }
2512
+
2513
+ template <class A, class T, int I, int... Is, detail::enable_sized_signed_t<T, 8> = 0>
2514
+ XSIMD_INLINE batch<T, A> bitwise_lshift(batch<T, A> const& lhs, int n, ::xsimd::detail::int_sequence<I, Is...>) noexcept
2515
+ {
2516
+ if (n == I)
2517
+ {
2518
+ return vshlq_n_s64(lhs, I);
2519
+ }
2520
+ else
2521
+ {
2522
+ return bitwise_lshift(lhs, n, ::xsimd::detail::int_sequence<Is...>());
2523
+ }
2524
+ }
2525
+
2526
+ template <class A, class T, int... Is>
2527
+ XSIMD_INLINE batch<T, A> bitwise_lshift_impl(batch<T, A> const& lhs, int n, ::xsimd::detail::int_sequence<0, Is...>) noexcept
2528
+ {
2529
+ if (n == 0)
2530
+ {
2531
+ return lhs;
2532
+ }
2533
+ else
2534
+ {
2535
+ return bitwise_lshift(lhs, n, ::xsimd::detail::int_sequence<Is...>());
2536
+ }
2537
+ }
2538
+
2539
+ template <class A, class T>
2540
+ XSIMD_INLINE bool shifts_all_positive(batch<T, A> const& b) noexcept
2541
+ {
2542
+ std::array<T, batch<T, A>::size> tmp = {};
2543
+ b.store_unaligned(tmp.begin());
2544
+ return std::all_of(tmp.begin(), tmp.end(), [](T x)
2545
+ { return x >= 0; });
2546
+ }
2547
+ }
2548
+
2549
+ template <class A, class T>
2550
+ XSIMD_INLINE batch<T, A> bitwise_lshift(batch<T, A> const& lhs, int n, requires_arch<neon>) noexcept
2551
+ {
2552
+ constexpr int size = sizeof(typename batch<T, A>::value_type) * 8;
2553
+ assert(0 <= n && n < size && "index in bounds");
2554
+ return detail::bitwise_lshift_impl(lhs, n, ::xsimd::detail::make_int_sequence<size>());
2555
+ }
2556
+
2557
+ template <class A, class T, detail::enable_sized_unsigned_t<T, 1> = 0>
2558
+ XSIMD_INLINE batch<T, A> bitwise_lshift(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon>) noexcept
2559
+ {
2560
+ // Blindly converting to signed since out of bounds shifts are UB anyways
2561
+ assert(detail::shifts_all_positive(rhs));
2562
+ return vshlq_u8(lhs, vreinterpretq_s8_u8(rhs));
2563
+ }
2564
+
2565
+ template <class A, class T, detail::enable_sized_signed_t<T, 1> = 0>
2566
+ XSIMD_INLINE batch<T, A> bitwise_lshift(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon>) noexcept
2567
+ {
2568
+ return vshlq_s8(lhs, rhs);
2569
+ }
2570
+
2571
+ template <class A, class T, detail::enable_sized_unsigned_t<T, 2> = 0>
2572
+ XSIMD_INLINE batch<T, A> bitwise_lshift(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon>) noexcept
2573
+ {
2574
+ // Blindly converting to signed since out of bounds shifts are UB anyways
2575
+ assert(detail::shifts_all_positive(rhs));
2576
+ return vshlq_u16(lhs, vreinterpretq_s16_u16(rhs));
2577
+ }
2578
+
2579
+ template <class A, class T, detail::enable_sized_signed_t<T, 2> = 0>
2580
+ XSIMD_INLINE batch<T, A> bitwise_lshift(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon>) noexcept
2581
+ {
2582
+ return vshlq_s16(lhs, rhs);
2583
+ }
2584
+
2585
+ template <class A, class T, detail::enable_sized_unsigned_t<T, 4> = 0>
2586
+ XSIMD_INLINE batch<T, A> bitwise_lshift(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon>) noexcept
2587
+ {
2588
+ // Blindly converting to signed since out of bounds shifts are UB anyways
2589
+ assert(detail::shifts_all_positive(rhs));
2590
+ return vshlq_u32(lhs, vreinterpretq_s32_u32(rhs));
2591
+ }
2592
+
2593
+ template <class A, class T, detail::enable_sized_signed_t<T, 4> = 0>
2594
+ XSIMD_INLINE batch<T, A> bitwise_lshift(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon>) noexcept
2595
+ {
2596
+ return vshlq_s32(lhs, rhs);
2597
+ }
2598
+
2599
+ template <class A, class T, detail::enable_sized_unsigned_t<T, 8> = 0>
2600
+ XSIMD_INLINE batch<T, A> bitwise_lshift(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon>) noexcept
2601
+ {
2602
+ // Blindly converting to signed since out of bounds shifts are UB
2603
+ assert(detail::shifts_all_positive(rhs));
2604
+ return vshlq_u64(lhs, vreinterpretq_s64_u64(rhs));
2605
+ }
2606
+
2607
+ template <class A, class T, detail::enable_sized_signed_t<T, 8> = 0>
2608
+ XSIMD_INLINE batch<T, A> bitwise_lshift(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon>) noexcept
2609
+ {
2610
+ return vshlq_s64(lhs, rhs);
2611
+ }
2612
+
2613
+ // immediate variant
2614
+ template <size_t shift, class A, class T, detail::enable_sized_unsigned_t<T, 1> = 0>
2615
+ XSIMD_INLINE batch<T, A> bitwise_lshift(batch<T, A> const& x, requires_arch<neon>) noexcept
2616
+ {
2617
+ return vshlq_n_u8(x, shift);
2618
+ }
2619
+
2620
+ template <size_t shift, class A, class T, detail::enable_sized_signed_t<T, 1> = 0>
2621
+ XSIMD_INLINE batch<T, A> bitwise_lshift(batch<T, A> const& x, requires_arch<neon>) noexcept
2622
+ {
2623
+ return vshlq_n_s8(x, shift);
2624
+ }
2625
+
2626
+ template <size_t shift, class A, class T, detail::enable_sized_unsigned_t<T, 2> = 0>
2627
+ XSIMD_INLINE batch<T, A> bitwise_lshift(batch<T, A> const& x, requires_arch<neon>) noexcept
2628
+ {
2629
+ return vshlq_n_u16(x, shift);
2630
+ }
2631
+
2632
+ template <size_t shift, class A, class T, detail::enable_sized_signed_t<T, 2> = 0>
2633
+ XSIMD_INLINE batch<T, A> bitwise_lshift(batch<T, A> const& x, requires_arch<neon>) noexcept
2634
+ {
2635
+ return vshlq_n_s16(x, shift);
2636
+ }
2637
+
2638
+ template <size_t shift, class A, class T, detail::enable_sized_unsigned_t<T, 4> = 0>
2639
+ XSIMD_INLINE batch<T, A> bitwise_lshift(batch<T, A> const& x, requires_arch<neon>) noexcept
2640
+ {
2641
+ return vshlq_n_u32(x, shift);
2642
+ }
2643
+
2644
+ template <size_t shift, class A, class T, detail::enable_sized_signed_t<T, 4> = 0>
2645
+ XSIMD_INLINE batch<T, A> bitwise_lshift(batch<T, A> const& x, requires_arch<neon>) noexcept
2646
+ {
2647
+ return vshlq_n_s32(x, shift);
2648
+ }
2649
+
2650
+ template <size_t shift, class A, class T, detail::enable_sized_unsigned_t<T, 8> = 0>
2651
+ XSIMD_INLINE batch<T, A> bitwise_lshift(batch<T, A> const& x, requires_arch<neon>) noexcept
2652
+ {
2653
+ return vshlq_n_u64(x, shift);
2654
+ }
2655
+
2656
+ template <size_t shift, class A, class T, detail::enable_sized_signed_t<T, 8> = 0>
2657
+ XSIMD_INLINE batch<T, A> bitwise_lshift(batch<T, A> const& x, requires_arch<neon>) noexcept
2658
+ {
2659
+ return vshlq_n_s64(x, shift);
2660
+ }
2661
+
2662
+ /******************
2663
+ * bitwise_rshift *
2664
+ ******************/
2665
+
2666
+ namespace detail
2667
+ {
2668
+ template <class A, class T>
2669
+ XSIMD_INLINE batch<T, A> bitwise_rshift(batch<T, A> const& /*lhs*/, int /*n*/, ::xsimd::detail::int_sequence<>) noexcept
2670
+ {
2671
+ assert(false && "bitwise_rshift out of bounds");
2672
+ return batch<T, A> {};
2673
+ }
2674
+
2675
+ template <class A, class T, int I, int... Is, detail::enable_sized_unsigned_t<T, 1> = 0>
2676
+ XSIMD_INLINE batch<T, A> bitwise_rshift(batch<T, A> const& lhs, int n, ::xsimd::detail::int_sequence<I, Is...>) noexcept
2677
+ {
2678
+ if (n == I)
2679
+ {
2680
+ return vshrq_n_u8(lhs, I);
2681
+ }
2682
+ else
2683
+ {
2684
+ return bitwise_rshift(lhs, n, ::xsimd::detail::int_sequence<Is...>());
2685
+ }
2686
+ }
2687
+
2688
+ template <class A, class T, int I, int... Is, detail::enable_sized_signed_t<T, 1> = 0>
2689
+ XSIMD_INLINE batch<T, A> bitwise_rshift(batch<T, A> const& lhs, int n, ::xsimd::detail::int_sequence<I, Is...>) noexcept
2690
+ {
2691
+ if (n == I)
2692
+ {
2693
+ return vshrq_n_s8(lhs, I);
2694
+ }
2695
+ else
2696
+ {
2697
+ return bitwise_rshift(lhs, n, ::xsimd::detail::int_sequence<Is...>());
2698
+ }
2699
+ }
2700
+
2701
+ template <class A, class T, int I, int... Is, detail::enable_sized_unsigned_t<T, 2> = 0>
2702
+ XSIMD_INLINE batch<T, A> bitwise_rshift(batch<T, A> const& lhs, int n, ::xsimd::detail::int_sequence<I, Is...>) noexcept
2703
+ {
2704
+ if (n == I)
2705
+ {
2706
+ return vshrq_n_u16(lhs, I);
2707
+ }
2708
+ else
2709
+ {
2710
+ return bitwise_rshift(lhs, n, ::xsimd::detail::int_sequence<Is...>());
2711
+ }
2712
+ }
2713
+
2714
+ template <class A, class T, int I, int... Is, detail::enable_sized_signed_t<T, 2> = 0>
2715
+ XSIMD_INLINE batch<T, A> bitwise_rshift(batch<T, A> const& lhs, int n, ::xsimd::detail::int_sequence<I, Is...>) noexcept
2716
+ {
2717
+ if (n == I)
2718
+ {
2719
+ return vshrq_n_s16(lhs, I);
2720
+ }
2721
+ else
2722
+ {
2723
+ return bitwise_rshift(lhs, n, ::xsimd::detail::int_sequence<Is...>());
2724
+ }
2725
+ }
2726
+
2727
+ template <class A, class T, int I, int... Is, detail::enable_sized_unsigned_t<T, 4> = 0>
2728
+ XSIMD_INLINE batch<T, A> bitwise_rshift(batch<T, A> const& lhs, int n, ::xsimd::detail::int_sequence<I, Is...>) noexcept
2729
+ {
2730
+ if (n == I)
2731
+ {
2732
+ return vshrq_n_u32(lhs, I);
2733
+ }
2734
+ else
2735
+ {
2736
+ return bitwise_rshift(lhs, n, ::xsimd::detail::int_sequence<Is...>());
2737
+ }
2738
+ }
2739
+
2740
+ template <class A, class T, int I, int... Is, detail::enable_sized_signed_t<T, 4> = 0>
2741
+ XSIMD_INLINE batch<T, A> bitwise_rshift(batch<T, A> const& lhs, int n, ::xsimd::detail::int_sequence<I, Is...>) noexcept
2742
+ {
2743
+ if (n == I)
2744
+ {
2745
+ return vshrq_n_s32(lhs, I);
2746
+ }
2747
+ else
2748
+ {
2749
+ return bitwise_rshift(lhs, n, ::xsimd::detail::int_sequence<Is...>());
2750
+ }
2751
+ }
2752
+
2753
+ template <class A, class T, int I, int... Is, detail::enable_sized_unsigned_t<T, 8> = 0>
2754
+ XSIMD_INLINE batch<T, A> bitwise_rshift(batch<T, A> const& lhs, int n, ::xsimd::detail::int_sequence<I, Is...>) noexcept
2755
+ {
2756
+ if (n == I)
2757
+ {
2758
+ return vshrq_n_u64(lhs, I);
2759
+ }
2760
+ else
2761
+ {
2762
+ return bitwise_rshift(lhs, n, ::xsimd::detail::int_sequence<Is...>());
2763
+ }
2764
+ }
2765
+
2766
+ template <class A, class T, int I, int... Is, detail::enable_sized_signed_t<T, 8> = 0>
2767
+ XSIMD_INLINE batch<T, A> bitwise_rshift(batch<T, A> const& lhs, int n, ::xsimd::detail::int_sequence<I, Is...>) noexcept
2768
+ {
2769
+ if (n == I)
2770
+ {
2771
+ return vshrq_n_s64(lhs, I);
2772
+ }
2773
+ else
2774
+ {
2775
+ return bitwise_rshift(lhs, n, ::xsimd::detail::int_sequence<Is...>());
2776
+ }
2777
+ }
2778
+
2779
+ template <class A, class T, int... Is>
2780
+ XSIMD_INLINE batch<T, A> bitwise_rshift_impl(batch<T, A> const& lhs, int n, ::xsimd::detail::int_sequence<0, Is...>) noexcept
2781
+ {
2782
+ if (n == 0)
2783
+ {
2784
+ return lhs;
2785
+ }
2786
+ else
2787
+ {
2788
+ return bitwise_rshift(lhs, n, ::xsimd::detail::int_sequence<Is...>());
2789
+ }
2790
+ }
2791
+ }
2792
+
2793
+ template <class A, class T>
2794
+ XSIMD_INLINE batch<T, A> bitwise_rshift(batch<T, A> const& lhs, int n, requires_arch<neon>) noexcept
2795
+ {
2796
+ constexpr int size = sizeof(typename batch<T, A>::value_type) * 8;
2797
+ assert(0 <= n && n < size && "index in bounds");
2798
+ return detail::bitwise_rshift_impl(lhs, n, ::xsimd::detail::make_int_sequence<size>());
2799
+ }
2800
+
2801
+ template <class A, class T, detail::enable_sized_unsigned_t<T, 1> = 0>
2802
+ XSIMD_INLINE batch<T, A> bitwise_rshift(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon>) noexcept
2803
+ {
2804
+ // Blindly converting to signed since out of bounds shifts are UB anyways
2805
+ assert(detail::shifts_all_positive(rhs));
2806
+ return vshlq_u8(lhs, vnegq_s8(vreinterpretq_s8_u8(rhs)));
2807
+ }
2808
+
2809
+ template <class A, class T, detail::enable_sized_signed_t<T, 1> = 0>
2810
+ XSIMD_INLINE batch<T, A> bitwise_rshift(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon>) noexcept
2811
+ {
2812
+ return vshlq_s8(lhs, vnegq_s8(rhs));
2813
+ }
2814
+
2815
+ template <class A, class T, detail::enable_sized_unsigned_t<T, 2> = 0>
2816
+ XSIMD_INLINE batch<T, A> bitwise_rshift(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon>) noexcept
2817
+ {
2818
+ // Blindly converting to signed since out of bounds shifts are UB anyways
2819
+ assert(detail::shifts_all_positive(rhs));
2820
+ return vshlq_u16(lhs, vnegq_s16(vreinterpretq_s16_u16(rhs)));
2821
+ }
2822
+
2823
+ template <class A, class T, detail::enable_sized_signed_t<T, 2> = 0>
2824
+ XSIMD_INLINE batch<T, A> bitwise_rshift(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon>) noexcept
2825
+ {
2826
+ return vshlq_s16(lhs, vnegq_s16(rhs));
2827
+ }
2828
+
2829
+ template <class A, class T, detail::enable_sized_unsigned_t<T, 4> = 0>
2830
+ XSIMD_INLINE batch<T, A> bitwise_rshift(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon>) noexcept
2831
+ {
2832
+ // Blindly converting to signed since out of bounds shifts are UB anyways
2833
+ assert(detail::shifts_all_positive(rhs));
2834
+ return vshlq_u32(lhs, vnegq_s32(vreinterpretq_s32_u32(rhs)));
2835
+ }
2836
+
2837
+ template <class A, class T, detail::enable_sized_signed_t<T, 4> = 0>
2838
+ XSIMD_INLINE batch<T, A> bitwise_rshift(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon>) noexcept
2839
+ {
2840
+ return vshlq_s32(lhs, vnegq_s32(rhs));
2841
+ }
2842
+
2843
+ template <class A, class T, detail::enable_sized_unsigned_t<T, 8> = 0>
2844
+ XSIMD_INLINE batch<T, A> bitwise_rshift(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon> req) noexcept
2845
+ {
2846
+ // Blindly converting to signed since out of bounds shifts are UB anyways
2847
+ assert(detail::shifts_all_positive(rhs));
2848
+ using S = std::make_signed_t<T>;
2849
+ return vshlq_u64(lhs, neg(batch<S, A>(vreinterpretq_s64_u64(rhs)), req).data);
2850
+ }
2851
+
2852
+ template <class A, class T, detail::enable_sized_signed_t<T, 8> = 0>
2853
+ XSIMD_INLINE batch<T, A> bitwise_rshift(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon>) noexcept
2854
+ {
2855
+ return vshlq_s64(lhs, neg(rhs, neon {}).data);
2856
+ }
2857
+
2858
+ // immediate variant
2859
+ template <size_t shift, class A, class T, detail::enable_sized_unsigned_t<T, 1> = 0>
2860
+ XSIMD_INLINE batch<T, A> bitwise_rshift(batch<T, A> const& x, requires_arch<neon>) noexcept
2861
+ {
2862
+ return vshrq_n_u8(x, shift);
2863
+ }
2864
+
2865
+ template <size_t shift, class A, class T, detail::enable_sized_signed_t<T, 1> = 0>
2866
+ XSIMD_INLINE batch<T, A> bitwise_rshift(batch<T, A> const& x, requires_arch<neon>) noexcept
2867
+ {
2868
+ return vshrq_n_s8(x, shift);
2869
+ }
2870
+
2871
+ template <size_t shift, class A, class T, detail::enable_sized_unsigned_t<T, 2> = 0>
2872
+ XSIMD_INLINE batch<T, A> bitwise_rshift(batch<T, A> const& x, requires_arch<neon>) noexcept
2873
+ {
2874
+ return vshrq_n_u16(x, shift);
2875
+ }
2876
+
2877
+ template <size_t shift, class A, class T, detail::enable_sized_signed_t<T, 2> = 0>
2878
+ XSIMD_INLINE batch<T, A> bitwise_rshift(batch<T, A> const& x, requires_arch<neon>) noexcept
2879
+ {
2880
+ return vshrq_n_s16(x, shift);
2881
+ }
2882
+
2883
+ template <size_t shift, class A, class T, detail::enable_sized_unsigned_t<T, 4> = 0>
2884
+ XSIMD_INLINE batch<T, A> bitwise_rshift(batch<T, A> const& x, requires_arch<neon>) noexcept
2885
+ {
2886
+ return vshrq_n_u32(x, shift);
2887
+ }
2888
+
2889
+ template <size_t shift, class A, class T, detail::enable_sized_signed_t<T, 4> = 0>
2890
+ XSIMD_INLINE batch<T, A> bitwise_rshift(batch<T, A> const& x, requires_arch<neon>) noexcept
2891
+ {
2892
+ return vshrq_n_s32(x, shift);
2893
+ }
2894
+
2895
+ template <size_t shift, class A, class T, detail::enable_sized_unsigned_t<T, 8> = 0>
2896
+ XSIMD_INLINE batch<T, A> bitwise_rshift(batch<T, A> const& x, requires_arch<neon>) noexcept
2897
+ {
2898
+ return vshrq_n_u64(x, shift);
2899
+ }
2900
+
2901
+ template <size_t shift, class A, class T, detail::enable_sized_signed_t<T, 8> = 0>
2902
+ XSIMD_INLINE batch<T, A> bitwise_rshift(batch<T, A> const& x, requires_arch<neon>) noexcept
2903
+ {
2904
+ return vshrq_n_s64(x, shift);
2905
+ }
2906
+
2907
+ // get
2908
+ template <class A, size_t I>
2909
+ XSIMD_INLINE float get(batch<float, A> const& self, ::xsimd::index<I>, requires_arch<neon>) noexcept
2910
+ {
2911
+ return vgetq_lane_f32(self, I);
2912
+ }
2913
+
2914
+ template <class A, size_t I, class T, detail::enable_sized_unsigned_t<T, 1> = 0>
2915
+ XSIMD_INLINE T get(batch<T, A> const& self, ::xsimd::index<I>, requires_arch<neon>) noexcept
2916
+ {
2917
+ return vgetq_lane_u8(self, I);
2918
+ }
2919
+
2920
+ template <class A, size_t I, class T, detail::enable_sized_signed_t<T, 1> = 0>
2921
+ XSIMD_INLINE T get(batch<T, A> const& self, ::xsimd::index<I>, requires_arch<neon>) noexcept
2922
+ {
2923
+ return vgetq_lane_s8(self, I);
2924
+ }
2925
+
2926
+ template <class A, size_t I, class T, detail::enable_sized_unsigned_t<T, 2> = 0>
2927
+ XSIMD_INLINE T get(batch<T, A> const& self, ::xsimd::index<I>, requires_arch<neon>) noexcept
2928
+ {
2929
+ return vgetq_lane_u16(self, I);
2930
+ }
2931
+
2932
+ template <class A, size_t I, class T, detail::enable_sized_signed_t<T, 2> = 0>
2933
+ XSIMD_INLINE T get(batch<T, A> const& self, ::xsimd::index<I>, requires_arch<neon>) noexcept
2934
+ {
2935
+ return vgetq_lane_s16(self, I);
2936
+ }
2937
+
2938
+ template <class A, size_t I, class T, detail::enable_sized_unsigned_t<T, 4> = 0>
2939
+ XSIMD_INLINE T get(batch<T, A> const& self, ::xsimd::index<I>, requires_arch<neon>) noexcept
2940
+ {
2941
+ return vgetq_lane_u32(self, I);
2942
+ }
2943
+
2944
+ template <class A, size_t I, class T, detail::enable_sized_signed_t<T, 4> = 0>
2945
+ XSIMD_INLINE T get(batch<T, A> const& self, ::xsimd::index<I>, requires_arch<neon>) noexcept
2946
+ {
2947
+ return vgetq_lane_s32(self, I);
2948
+ }
2949
+
2950
+ template <class A, size_t I, class T, detail::enable_sized_unsigned_t<T, 8> = 0>
2951
+ XSIMD_INLINE T get(batch<T, A> const& self, ::xsimd::index<I>, requires_arch<neon>) noexcept
2952
+ {
2953
+ return vgetq_lane_u64(self, I);
2954
+ }
2955
+
2956
+ template <class A, size_t I, class T, detail::enable_sized_signed_t<T, 8> = 0>
2957
+ XSIMD_INLINE T get(batch<T, A> const& self, ::xsimd::index<I>, requires_arch<neon>) noexcept
2958
+ {
2959
+ return vgetq_lane_s64(self, I);
2960
+ }
2961
+
2962
+ // first
2963
+ template <class A>
2964
+ XSIMD_INLINE float first(batch<float, A> const& self, requires_arch<neon>) noexcept
2965
+ {
2966
+ return vgetq_lane_f32(self, 0);
2967
+ }
2968
+
2969
+ template <class A, class T, detail::enable_sized_unsigned_t<T, 1> = 0>
2970
+ XSIMD_INLINE T first(batch<T, A> val, requires_arch<neon>) noexcept
2971
+ {
2972
+ return vgetq_lane_u8(val, 0);
2973
+ }
2974
+
2975
+ template <class A, class T, detail::enable_sized_signed_t<T, 1> = 0>
2976
+ XSIMD_INLINE T first(batch<T, A> val, requires_arch<neon>) noexcept
2977
+ {
2978
+ return vgetq_lane_s8(val, 0);
2979
+ }
2980
+
2981
+ template <class A, class T, detail::enable_sized_unsigned_t<T, 2> = 0>
2982
+ XSIMD_INLINE T first(batch<T, A> val, requires_arch<neon>) noexcept
2983
+ {
2984
+ return vgetq_lane_u16(val, 0);
2985
+ }
2986
+
2987
+ template <class A, class T, detail::enable_sized_signed_t<T, 2> = 0>
2988
+ XSIMD_INLINE T first(batch<T, A> val, requires_arch<neon>) noexcept
2989
+ {
2990
+ return vgetq_lane_s16(val, 0);
2991
+ }
2992
+
2993
+ template <class A, class T, detail::enable_sized_unsigned_t<T, 4> = 0>
2994
+ XSIMD_INLINE T first(batch<T, A> val, requires_arch<neon>) noexcept
2995
+ {
2996
+ return vgetq_lane_u32(val, 0);
2997
+ }
2998
+
2999
+ template <class A, class T, detail::enable_sized_signed_t<T, 4> = 0>
3000
+ XSIMD_INLINE T first(batch<T, A> val, requires_arch<neon>) noexcept
3001
+ {
3002
+ return vgetq_lane_s32(val, 0);
3003
+ }
3004
+
3005
+ template <class A, class T, detail::enable_sized_unsigned_t<T, 8> = 0>
3006
+ XSIMD_INLINE T first(batch<T, A> val, requires_arch<neon>) noexcept
3007
+ {
3008
+ return vgetq_lane_u64(val, 0);
3009
+ }
3010
+
3011
+ template <class A, class T, detail::enable_sized_signed_t<T, 8> = 0>
3012
+ XSIMD_INLINE T first(batch<T, A> val, requires_arch<neon>) noexcept
3013
+ {
3014
+ return vgetq_lane_s64(val, 0);
3015
+ }
3016
+
3017
+ // Overloads of bitwise shifts accepting two batches of uint64/int64 are not available with ARMv7
3018
+
3019
+ /*******
3020
+ * all *
3021
+ *******/
3022
+
3023
+ template <class A, class T, detail::enable_sized_t<T, 8> = 0>
3024
+ XSIMD_INLINE bool all(batch_bool<T, A> const& arg, requires_arch<neon>) noexcept
3025
+ {
3026
+ uint64x1_t tmp = vand_u64(vget_low_u64(arg), vget_high_u64(arg));
3027
+ return vget_lane_u64(tmp, 0) == ~0ULL;
3028
+ }
3029
+
3030
+ template <class A, class T, detail::enable_sized_t<T, 1> = 0>
3031
+ XSIMD_INLINE bool all(batch_bool<T, A> const& arg, requires_arch<neon>) noexcept
3032
+ {
3033
+ return all(batch_bool<uint64_t, A>(vreinterpretq_u64_u8(arg)), neon {});
3034
+ }
3035
+
3036
+ template <class A, class T, detail::enable_sized_t<T, 2> = 0>
3037
+ XSIMD_INLINE bool all(batch_bool<T, A> const& arg, requires_arch<neon>) noexcept
3038
+ {
3039
+ return all(batch_bool<uint64_t, A>(vreinterpretq_u64_u16(arg)), neon {});
3040
+ }
3041
+
3042
+ template <class A, class T, detail::enable_sized_t<T, 4> = 0>
3043
+ XSIMD_INLINE bool all(batch_bool<T, A> const& arg, requires_arch<neon>) noexcept
3044
+ {
3045
+ return all(batch_bool<uint64_t, A>(vreinterpretq_u64_u32(arg)), neon {});
3046
+ }
3047
+
3048
+ /*******
3049
+ * any *
3050
+ *******/
3051
+
3052
+ template <class A, class T, detail::enable_sized_t<T, 8> = 0>
3053
+ XSIMD_INLINE bool any(batch_bool<T, A> const& arg, requires_arch<neon>) noexcept
3054
+ {
3055
+ uint32x2_t tmp = vqmovn_u64(arg);
3056
+ return vget_lane_u64(vreinterpret_u64_u32(tmp), 0) != 0;
3057
+ }
3058
+
3059
+ template <class A, class T, detail::enable_sized_t<T, 1> = 0>
3060
+ XSIMD_INLINE bool any(batch_bool<T, A> const& arg, requires_arch<neon>) noexcept
3061
+ {
3062
+ return any(batch_bool<uint64_t, A>(vreinterpretq_u64_u8(arg)), neon {});
3063
+ }
3064
+
3065
+ template <class A, class T, detail::enable_sized_t<T, 2> = 0>
3066
+ XSIMD_INLINE bool any(batch_bool<T, A> const& arg, requires_arch<neon>) noexcept
3067
+ {
3068
+ return any(batch_bool<uint64_t, A>(vreinterpretq_u64_u16(arg)), neon {});
3069
+ }
3070
+
3071
+ template <class A, class T, detail::enable_sized_t<T, 4> = 0>
3072
+ XSIMD_INLINE bool any(batch_bool<T, A> const& arg, requires_arch<neon>) noexcept
3073
+ {
3074
+ return any(batch_bool<uint64_t, A>(vreinterpretq_u64_u32(arg)), neon {});
3075
+ }
3076
+
3077
+ /*********
3078
+ * isnan *
3079
+ *********/
3080
+
3081
+ template <class A>
3082
+ XSIMD_INLINE batch_bool<float, A> isnan(batch<float, A> const& arg, requires_arch<neon>) noexcept
3083
+ {
3084
+ return !(arg == arg);
3085
+ }
3086
+
3087
+ // slide_left
3088
+ namespace detail
3089
+ {
3090
+ template <size_t N>
3091
+ struct slider_left
3092
+ {
3093
+ template <class A, class T>
3094
+ XSIMD_INLINE batch<T, A> operator()(batch<T, A> const& x, requires_arch<neon>) noexcept
3095
+ {
3096
+ const auto left = vdupq_n_u8(0);
3097
+ const auto right = bitwise_cast<uint8_t>(x).data;
3098
+ const batch<uint8_t, A> res(vextq_u8(left, right, 16 - N));
3099
+ return bitwise_cast<T>(res);
3100
+ }
3101
+ };
3102
+
3103
+ template <>
3104
+ struct slider_left<0>
3105
+ {
3106
+ template <class A, class T>
3107
+ XSIMD_INLINE batch<T, A> operator()(batch<T, A> const& x, requires_arch<neon>) noexcept
3108
+ {
3109
+ return x;
3110
+ }
3111
+ };
3112
+ } // namespace detail
3113
+
3114
+ template <size_t N, class A, class T>
3115
+ XSIMD_INLINE batch<T, A> slide_left(batch<T, A> const& x, requires_arch<neon>) noexcept
3116
+ {
3117
+ return detail::slider_left<N> {}(x, A {});
3118
+ }
3119
+
3120
+ // slide_right
3121
+ namespace detail
3122
+ {
3123
+ template <size_t N>
3124
+ struct slider_right
3125
+ {
3126
+ template <class A, class T>
3127
+ XSIMD_INLINE batch<T, A> operator()(batch<T, A> const& x, requires_arch<neon>) noexcept
3128
+ {
3129
+ const auto left = bitwise_cast<uint8_t>(x).data;
3130
+ const auto right = vdupq_n_u8(0);
3131
+ const batch<uint8_t, A> res(vextq_u8(left, right, N));
3132
+ return bitwise_cast<T>(res);
3133
+ }
3134
+ };
3135
+
3136
+ template <>
3137
+ struct slider_right<16>
3138
+ {
3139
+ template <class A, class T>
3140
+ XSIMD_INLINE batch<T, A> operator()(batch<T, A> const&, requires_arch<neon>) noexcept
3141
+ {
3142
+ return batch<T, A> {};
3143
+ }
3144
+ };
3145
+ } // namespace detail
3146
+
3147
+ template <size_t N, class A, class T>
3148
+ XSIMD_INLINE batch<T, A> slide_right(batch<T, A> const& x, requires_arch<neon>) noexcept
3149
+ {
3150
+ return detail::slider_right<N> {}(x, A {});
3151
+ }
3152
+
3153
+ /****************
3154
+ * rotate_left *
3155
+ ****************/
3156
+ namespace wrap
3157
+ {
3158
+ // TODO(c++17): Make a single function with if constexpr switch
3159
+ // Templating on the scalar type `T` is required because in some compilers (e.g. MSVC)
3160
+ // the vector types are all aliases of the same type.
3161
+ template <size_t N, class T, std::enable_if_t<std::is_same<T, uint8_t>::value, int> = 0>
3162
+ XSIMD_INLINE uint8x16_t x_rotate_left(uint8x16_t a, uint8x16_t b) noexcept { return vextq_u8(a, b, N); }
3163
+ template <size_t N, class T, std::enable_if_t<std::is_same<T, int8_t>::value, int> = 0>
3164
+ XSIMD_INLINE int8x16_t x_rotate_left(int8x16_t a, int8x16_t b) noexcept { return vextq_s8(a, b, N); }
3165
+ template <size_t N, class T, std::enable_if_t<std::is_same<T, uint16_t>::value, int> = 0>
3166
+ XSIMD_INLINE uint16x8_t x_rotate_left(uint16x8_t a, uint16x8_t b) noexcept { return vextq_u16(a, b, N % 8); }
3167
+ template <size_t N, class T, std::enable_if_t<std::is_same<T, int16_t>::value, int> = 0>
3168
+ XSIMD_INLINE int16x8_t x_rotate_left(int16x8_t a, int16x8_t b) noexcept { return vextq_s16(a, b, N % 8); }
3169
+ template <size_t N, class T, std::enable_if_t<std::is_same<T, uint32_t>::value, int> = 0>
3170
+ XSIMD_INLINE uint32x4_t x_rotate_left(uint32x4_t a, uint32x4_t b) noexcept { return vextq_u32(a, b, N % 4); }
3171
+ template <size_t N, class T, std::enable_if_t<std::is_same<T, int32_t>::value, int> = 0>
3172
+ XSIMD_INLINE int32x4_t x_rotate_left(int32x4_t a, int32x4_t b) noexcept { return vextq_s32(a, b, N % 4); }
3173
+ template <size_t N, class T, std::enable_if_t<std::is_same<T, uint64_t>::value, int> = 0>
3174
+ XSIMD_INLINE uint64x2_t x_rotate_left(uint64x2_t a, uint64x2_t b) noexcept { return vextq_u64(a, b, N % 2); }
3175
+ template <size_t N, class T, std::enable_if_t<std::is_same<T, int64_t>::value, int> = 0>
3176
+ XSIMD_INLINE int64x2_t x_rotate_left(int64x2_t a, int64x2_t b) noexcept { return vextq_s64(a, b, N % 2); }
3177
+ template <size_t N, class T, std::enable_if_t<std::is_same<T, float>::value, int> = 0>
3178
+ XSIMD_INLINE float32x4_t x_rotate_left(float32x4_t a, float32x4_t b) noexcept { return vextq_f32(a, b, N % 4); }
3179
+ }
3180
+
3181
+ template <size_t N, class A, class T, detail::enable_neon_type_t<T> = 0>
3182
+ XSIMD_INLINE batch<T, A> rotate_left(batch<T, A> const& a, requires_arch<neon>) noexcept
3183
+ {
3184
+ using register_type = typename batch<T, A>::register_type;
3185
+ return wrap::x_rotate_left<N, map_to_sized_type_t<T>>(register_type(a), register_type(a));
3186
+ }
3187
+ }
3188
+
3189
+ template <typename T, class A, T... Values>
3190
+ struct batch_constant;
3191
+
3192
+ namespace kernel
3193
+ {
3194
+ /***********
3195
+ * swizzle *
3196
+ ***********/
3197
+
3198
+ template <class A, class T, class I, I... idx>
3199
+ XSIMD_INLINE batch<T, A> swizzle(batch<T, A> const& self,
3200
+ batch_constant<I, A, idx...>,
3201
+ requires_arch<neon>) noexcept
3202
+ {
3203
+ static_assert(batch<T, A>::size == sizeof...(idx), "valid swizzle indices");
3204
+ std::array<T, batch<T, A>::size> data;
3205
+ self.store_aligned(data.data());
3206
+ return set(batch<T, A>(), A(), data[idx]...);
3207
+ }
3208
+
3209
+ template <class A, uint64_t V0, uint64_t V1>
3210
+ XSIMD_INLINE batch<uint64_t, A> swizzle(batch<uint64_t, A> const& self,
3211
+ batch_constant<uint64_t, A, V0, V1>,
3212
+ requires_arch<neon>) noexcept
3213
+ {
3214
+ XSIMD_IF_CONSTEXPR(V0 == 0 && V1 == 0)
3215
+ {
3216
+ auto lo = vget_low_u64(self);
3217
+ return vcombine_u64(lo, lo);
3218
+ }
3219
+ XSIMD_IF_CONSTEXPR(V0 == 1 && V1 == 1)
3220
+ {
3221
+ auto hi = vget_high_u64(self);
3222
+ return vcombine_u64(hi, hi);
3223
+ }
3224
+ XSIMD_IF_CONSTEXPR(V0 == 0 && V1 == 1)
3225
+ {
3226
+ return self;
3227
+ }
3228
+ else
3229
+ {
3230
+ return vextq_u64(self, self, 1);
3231
+ }
3232
+ }
3233
+
3234
+ template <class A, uint64_t V0, uint64_t V1>
3235
+ XSIMD_INLINE batch<int64_t, A> swizzle(batch<int64_t, A> const& self,
3236
+ batch_constant<int64_t, A, V0, V1> mask,
3237
+ requires_arch<neon>) noexcept
3238
+ {
3239
+ return vreinterpretq_s64_u64(swizzle(vreinterpretq_u64_s64(self), mask, A {}));
3240
+ }
3241
+
3242
+ namespace detail
3243
+ {
3244
+ template <uint32_t Va, uint32_t Vb>
3245
+ XSIMD_INLINE uint8x8_t make_mask()
3246
+ {
3247
+ uint8x8_t res = {
3248
+ static_cast<uint8_t>((Va % 2) * 4 + 0),
3249
+ static_cast<uint8_t>((Va % 2) * 4 + 1),
3250
+ static_cast<uint8_t>((Va % 2) * 4 + 2),
3251
+ static_cast<uint8_t>((Va % 2) * 4 + 3),
3252
+ static_cast<uint8_t>((Vb % 2) * 4 + 0),
3253
+ static_cast<uint8_t>((Vb % 2) * 4 + 1),
3254
+ static_cast<uint8_t>((Vb % 2) * 4 + 2),
3255
+ static_cast<uint8_t>((Vb % 2) * 4 + 3),
3256
+ };
3257
+ return res;
3258
+ }
3259
+ }
3260
+
3261
+ template <class A, uint32_t V0, uint32_t V1, uint32_t V2, uint32_t V3>
3262
+ XSIMD_INLINE batch<uint32_t, A> swizzle(batch<uint32_t, A> const& self,
3263
+ batch_constant<uint32_t, A, V0, V1, V2, V3> mask,
3264
+ requires_arch<neon>) noexcept
3265
+ {
3266
+ constexpr bool is_identity = detail::is_identity(mask);
3267
+ constexpr bool is_dup_lo = detail::is_dup_lo(mask);
3268
+ constexpr bool is_dup_hi = detail::is_dup_hi(mask);
3269
+
3270
+ XSIMD_IF_CONSTEXPR(is_identity)
3271
+ {
3272
+ return self;
3273
+ }
3274
+ XSIMD_IF_CONSTEXPR(is_dup_lo)
3275
+ {
3276
+ XSIMD_IF_CONSTEXPR(V0 == 0 && V1 == 1)
3277
+ {
3278
+ return vreinterpretq_u32_u64(vdupq_lane_u64(vget_low_u64(vreinterpretq_u64_u32(self)), 0));
3279
+ }
3280
+ XSIMD_IF_CONSTEXPR(V0 == 1 && V1 == 0)
3281
+ {
3282
+ return vreinterpretq_u32_u64(vdupq_lane_u64(vreinterpret_u64_u32(vrev64_u32(vget_low_u32(self))), 0));
3283
+ }
3284
+ return vdupq_n_u32(vgetq_lane_u32(self, V0));
3285
+ }
3286
+ XSIMD_IF_CONSTEXPR(is_dup_hi)
3287
+ {
3288
+ XSIMD_IF_CONSTEXPR(V0 == 2 && V1 == 3)
3289
+ {
3290
+ return vreinterpretq_u32_u64(vdupq_lane_u64(vget_high_u64(vreinterpretq_u64_u32(self)), 0));
3291
+ }
3292
+ XSIMD_IF_CONSTEXPR(V0 == 3 && V1 == 2)
3293
+ {
3294
+ return vreinterpretq_u32_u64(vdupq_lane_u64(vreinterpret_u64_u32(vrev64_u32(vget_high_u32(self))), 0));
3295
+ }
3296
+ return vdupq_n_u32(vgetq_lane_u32(self, V0));
3297
+ }
3298
+ XSIMD_IF_CONSTEXPR(V0 < 2 && V1 < 2 && V2 < 2 && V3 < 2)
3299
+ {
3300
+ uint8x8_t low = vreinterpret_u8_u64(vget_low_u64(vreinterpretq_u64_u32(self)));
3301
+ uint8x8_t mask_lo = detail::make_mask<V0, V1>();
3302
+ uint8x8_t mask_hi = detail::make_mask<V2, V3>();
3303
+ uint8x8_t lo = vtbl1_u8(low, mask_lo);
3304
+ uint8x8_t hi = vtbl1_u8(low, mask_hi);
3305
+ return vreinterpretq_u32_u8(vcombine_u8(lo, hi));
3306
+ }
3307
+ XSIMD_IF_CONSTEXPR(V0 >= 2 && V1 >= 2 && V2 >= 2 && V3 >= 2)
3308
+ {
3309
+ uint8x8_t high = vreinterpret_u8_u64(vget_high_u64(vreinterpretq_u64_u32(self)));
3310
+ uint8x8_t mask_lo = detail::make_mask<V0, V1>();
3311
+ uint8x8_t mask_hi = detail::make_mask<V2, V3>();
3312
+ uint8x8_t lo = vtbl1_u8(high, mask_lo);
3313
+ uint8x8_t hi = vtbl1_u8(high, mask_hi);
3314
+ return vreinterpretq_u32_u8(vcombine_u8(lo, hi));
3315
+ }
3316
+
3317
+ uint8x8_t mask_lo = detail::make_mask<V0, V1>();
3318
+ uint8x8_t mask_hi = detail::make_mask<V2, V3>();
3319
+
3320
+ uint8x8_t low = vreinterpret_u8_u64(vget_low_u64(vreinterpretq_u64_u32(self)));
3321
+ uint8x8_t lol = vtbl1_u8(low, mask_lo);
3322
+ uint8x8_t loh = vtbl1_u8(low, mask_hi);
3323
+ uint32x4_t true_br = vreinterpretq_u32_u8(vcombine_u8(lol, loh));
3324
+
3325
+ uint8x8_t high = vreinterpret_u8_u64(vget_high_u64(vreinterpretq_u64_u32(self)));
3326
+ uint8x8_t hil = vtbl1_u8(high, mask_lo);
3327
+ uint8x8_t hih = vtbl1_u8(high, mask_hi);
3328
+ uint32x4_t false_br = vreinterpretq_u32_u8(vcombine_u8(hil, hih));
3329
+
3330
+ batch_bool_constant<uint32_t, A, (V0 < 2), (V1 < 2), (V2 < 2), (V3 < 2)> blend_mask;
3331
+ return select(blend_mask, batch<uint32_t, A>(true_br), batch<uint32_t, A>(false_br), A {});
3332
+ }
3333
+
3334
+ template <class A, uint32_t V0, uint32_t V1, uint32_t V2, uint32_t V3>
3335
+ XSIMD_INLINE batch<int32_t, A> swizzle(batch<int32_t, A> const& self,
3336
+ batch_constant<int32_t, A, V0, V1, V2, V3> mask,
3337
+ requires_arch<neon>) noexcept
3338
+ {
3339
+ return vreinterpretq_s32_u32(swizzle(vreinterpretq_u32_s32(self), mask, A {}));
3340
+ }
3341
+
3342
+ template <class A, uint32_t V0, uint32_t V1, uint32_t V2, uint32_t V3>
3343
+ XSIMD_INLINE batch<float, A> swizzle(batch<float, A> const& self,
3344
+ batch_constant<uint32_t, A, V0, V1, V2, V3> mask,
3345
+ requires_arch<neon>) noexcept
3346
+ {
3347
+ return vreinterpretq_f32_u32(swizzle(batch<uint32_t, A>(vreinterpretq_u32_f32(self)), mask, A {}));
3348
+ }
3349
+
3350
+ /*********
3351
+ * widen *
3352
+ *********/
3353
+ template <class A, class T, detail::enable_sized_signed_t<T, 1> = 0>
3354
+ XSIMD_INLINE std::array<batch<widen_t<T>, A>, 2> widen(batch<T, A> const& x, requires_arch<neon>) noexcept
3355
+ {
3356
+ return { batch<widen_t<T>, A>(vaddl_s8(vget_low_s8(x), vdup_n_s8(0))), batch<widen_t<T>, A>(vaddl_s8(vget_high_s8(x), vdup_n_s8(0))) };
3357
+ }
3358
+ template <class A, class T, detail::enable_sized_unsigned_t<T, 1> = 0>
3359
+ XSIMD_INLINE std::array<batch<widen_t<T>, A>, 2> widen(batch<T, A> const& x, requires_arch<neon>) noexcept
3360
+ {
3361
+ return { batch<widen_t<T>, A>(vaddl_u8(vget_low_u8(x), vdup_n_u8(0))), batch<widen_t<T>, A>(vaddl_u8(vget_high_u8(x), vdup_n_u8(0))) };
3362
+ }
3363
+ template <class A, class T, detail::enable_sized_signed_t<T, 2> = 0>
3364
+ XSIMD_INLINE std::array<batch<widen_t<T>, A>, 2> widen(batch<T, A> const& x, requires_arch<neon>) noexcept
3365
+ {
3366
+ return { batch<widen_t<T>, A>(vaddl_s16(vget_low_s16(x), vdup_n_s16(0))), batch<widen_t<T>, A>(vaddl_s16(vget_high_s16(x), vdup_n_s16(0))) };
3367
+ }
3368
+ template <class A, class T, detail::enable_sized_unsigned_t<T, 2> = 0>
3369
+ XSIMD_INLINE std::array<batch<widen_t<T>, A>, 2> widen(batch<T, A> const& x, requires_arch<neon>) noexcept
3370
+ {
3371
+ return { batch<widen_t<T>, A>(vaddl_u16(vget_low_u16(x), vdup_n_u16(0))), batch<widen_t<T>, A>(vaddl_u16(vget_high_u16(x), vdup_n_u16(0))) };
3372
+ }
3373
+ template <class A, class T, detail::enable_sized_signed_t<T, 4> = 0>
3374
+ XSIMD_INLINE std::array<batch<widen_t<T>, A>, 2> widen(batch<T, A> const& x, requires_arch<neon>) noexcept
3375
+ {
3376
+ return { batch<widen_t<T>, A>(vaddl_s32(vget_low_s32(x), vdup_n_s32(0))), batch<widen_t<T>, A>(vaddl_s32(vget_high_s32(x), vdup_n_s32(0))) };
3377
+ }
3378
+ template <class A, class T, detail::enable_sized_unsigned_t<T, 4> = 0>
3379
+ XSIMD_INLINE std::array<batch<widen_t<T>, A>, 2> widen(batch<T, A> const& x, requires_arch<neon>) noexcept
3380
+ {
3381
+ return { batch<widen_t<T>, A>(vaddl_u32(vget_low_u32(x), vdup_n_u32(0))), batch<widen_t<T>, A>(vaddl_u32(vget_high_u32(x), vdup_n_u32(0))) };
3382
+ }
3383
+
3384
+ /********
3385
+ * mask *
3386
+ ********/
3387
+ namespace detail
3388
+ {
3389
+ #ifdef XSIMD_LITTLE_ENDIAN
3390
+ static constexpr bool do_swap = false;
3391
+ #else
3392
+ static constexpr bool do_swap = true;
3393
+ #endif
3394
+ }
3395
+
3396
+ template <class A, class T, detail::enable_sized_t<T, 1> = 0>
3397
+ XSIMD_INLINE uint64_t mask(batch_bool<T, A> const& self, requires_arch<neon>) noexcept
3398
+ {
3399
+ // From https://github.com/DLTcollab/sse2neon/blob/master/sse2neon.h
3400
+ uint8x16_t msbs = vshrq_n_u8(self, 7);
3401
+ XSIMD_IF_CONSTEXPR(detail::do_swap)
3402
+ {
3403
+ msbs = vrev64q_u8(msbs);
3404
+ }
3405
+
3406
+ uint64x2_t bits = vreinterpretq_u64_u8(msbs);
3407
+ bits = vsraq_n_u64(bits, bits, 7);
3408
+ bits = vsraq_n_u64(bits, bits, 14);
3409
+ bits = vsraq_n_u64(bits, bits, 28);
3410
+
3411
+ uint8x16_t output = vreinterpretq_u8_u64(bits);
3412
+ constexpr int offset = detail::do_swap ? 7 : 0;
3413
+
3414
+ return vgetq_lane_u8(output, offset) | vgetq_lane_u8(output, offset + 8) << 8;
3415
+ }
3416
+
3417
+ template <class A, class T, detail::enable_sized_t<T, 2> = 0>
3418
+ XSIMD_INLINE uint64_t mask(batch_bool<T, A> const& self, requires_arch<neon>) noexcept
3419
+ {
3420
+ // Adapted from https://github.com/DLTcollab/sse2neon/blob/master/sse2neon.h
3421
+ uint16x8_t msbs = vshrq_n_u16(self, 15);
3422
+ XSIMD_IF_CONSTEXPR(detail::do_swap)
3423
+ {
3424
+ msbs = vrev64q_u16(msbs);
3425
+ }
3426
+
3427
+ uint64x2_t bits = vreinterpretq_u64_u16(msbs);
3428
+ bits = vsraq_n_u64(bits, bits, 15);
3429
+ bits = vsraq_n_u64(bits, bits, 30);
3430
+
3431
+ uint8x16_t output = vreinterpretq_u8_u64(bits);
3432
+ constexpr int offset = detail::do_swap ? 7 : 0;
3433
+
3434
+ return vgetq_lane_u8(output, offset) | vgetq_lane_u8(output, offset + 8) << 4;
3435
+ }
3436
+
3437
+ template <class A, class T, detail::enable_sized_t<T, 4> = 0>
3438
+ XSIMD_INLINE uint64_t mask(batch_bool<T, A> const& self, requires_arch<neon>) noexcept
3439
+ {
3440
+ // Adapted from https://github.com/DLTcollab/sse2neon/blob/master/sse2neon.h
3441
+ uint32x4_t msbs = vshrq_n_u32(self, 31);
3442
+ XSIMD_IF_CONSTEXPR(detail::do_swap)
3443
+ {
3444
+ msbs = vrev64q_u32(msbs);
3445
+ }
3446
+
3447
+ uint64x2_t bits = vreinterpretq_u64_u32(msbs);
3448
+ bits = vsraq_n_u64(bits, bits, 31);
3449
+
3450
+ uint8x16_t output = vreinterpretq_u8_u64(bits);
3451
+ constexpr int offset = detail::do_swap ? 7 : 0;
3452
+
3453
+ return vgetq_lane_u8(output, offset) | vgetq_lane_u8(output, offset + 8) << 2;
3454
+ }
3455
+
3456
+ template <class A, class T, detail::enable_sized_t<T, 8> = 0>
3457
+ XSIMD_INLINE uint64_t mask(batch_bool<T, A> const& self, requires_arch<neon>) noexcept
3458
+ {
3459
+ uint64_t mask_lo = vgetq_lane_u64(self, 0);
3460
+ uint64_t mask_hi = vgetq_lane_u64(self, 1);
3461
+ return ((mask_lo >> 63) | (mask_hi << 1)) & 0x3;
3462
+ }
3463
+
3464
+ /*********
3465
+ * count *
3466
+ *********/
3467
+
3468
+ // NOTE: Extracting a u32 for the return value saves two instructions on 32-bit ARM:
3469
+ // <https://godbolt.org/z/PYn4na8sY>.
3470
+
3471
+ template <class A, class T, detail::enable_sized_t<T, 1> = 0>
3472
+ XSIMD_INLINE size_t count(batch_bool<T, A> const& self, requires_arch<neon>) noexcept
3473
+ {
3474
+ uint8x16_t msbs = vshrq_n_u8(self, 7);
3475
+ uint64x2_t psum = vpaddlq_u32(vpaddlq_u16(vpaddlq_u8(msbs)));
3476
+ uint64x1_t total = vadd_u64(vget_low_u64(psum), vget_high_u64(psum));
3477
+
3478
+ assert(vget_lane_u64(total, 0) <= std::numeric_limits<uint32_t>::max());
3479
+ return vget_lane_u32(vreinterpret_u32_u64(total), 0);
3480
+ }
3481
+
3482
+ template <class A, class T, detail::enable_sized_t<T, 2> = 0>
3483
+ XSIMD_INLINE size_t count(batch_bool<T, A> const& self, requires_arch<neon>) noexcept
3484
+ {
3485
+ uint16x8_t msbs = vshrq_n_u16(self, 15);
3486
+ uint64x2_t psum = vpaddlq_u32(vpaddlq_u16(msbs));
3487
+ uint64x1_t total = vadd_u64(vget_low_u64(psum), vget_high_u64(psum));
3488
+
3489
+ assert(vget_lane_u64(total, 0) <= std::numeric_limits<uint32_t>::max());
3490
+ return vget_lane_u32(vreinterpret_u32_u64(total), 0);
3491
+ }
3492
+
3493
+ template <class A, class T, detail::enable_sized_t<T, 4> = 0>
3494
+ XSIMD_INLINE size_t count(batch_bool<T, A> const& self, requires_arch<neon>) noexcept
3495
+ {
3496
+ uint32x4_t msbs = vshrq_n_u32(self, 31);
3497
+ uint64x2_t psum = vpaddlq_u32(msbs);
3498
+ uint64x1_t total = vadd_u64(vget_low_u64(psum), vget_high_u64(psum));
3499
+
3500
+ assert(vget_lane_u64(total, 0) <= std::numeric_limits<uint32_t>::max());
3501
+ return vget_lane_u32(vreinterpret_u32_u64(total), 0);
3502
+ }
3503
+
3504
+ template <class A, class T, detail::enable_sized_t<T, 8> = 0>
3505
+ XSIMD_INLINE size_t count(batch_bool<T, A> const& self, requires_arch<neon>) noexcept
3506
+ {
3507
+ uint64x2_t msbs = vshrq_n_u64(self, 63);
3508
+ uint64x1_t total = vadd_u64(vget_low_u64(msbs), vget_high_u64(msbs));
3509
+
3510
+ assert(vget_lane_u64(total, 0) <= std::numeric_limits<uint32_t>::max());
3511
+ return vget_lane_u32(vreinterpret_u32_u64(total), 0);
3512
+ }
3513
+
3514
+ #define WRAP_MASK_OP(OP) \
3515
+ template <class A, class T, detail::enable_sized_t<T, 1> = 0> \
3516
+ XSIMD_INLINE size_t OP(batch_bool<T, A> const& self, requires_arch<neon>) noexcept \
3517
+ { \
3518
+ uint8x16_t inner = self; \
3519
+ XSIMD_IF_CONSTEXPR(detail::do_swap) \
3520
+ { \
3521
+ inner = vrev16q_u8(inner); \
3522
+ } \
3523
+ \
3524
+ uint8x8_t narrowed = vshrn_n_u16(vreinterpretq_u16_u8(inner), 4); \
3525
+ XSIMD_IF_CONSTEXPR(detail::do_swap) \
3526
+ { \
3527
+ narrowed = vrev64_u8(narrowed); \
3528
+ } \
3529
+ \
3530
+ uint64_t result = vget_lane_u64(vreinterpret_u64_u8(narrowed), 0); \
3531
+ return xsimd::detail::OP(result) / 4; \
3532
+ } \
3533
+ template <class A, class T, detail::enable_sized_t<T, 2> = 0> \
3534
+ XSIMD_INLINE size_t OP(batch_bool<T, A> const& self, requires_arch<neon>) noexcept \
3535
+ { \
3536
+ uint8x8_t narrowed = vmovn_u16(self); \
3537
+ XSIMD_IF_CONSTEXPR(detail::do_swap) \
3538
+ { \
3539
+ narrowed = vrev64_u8(narrowed); \
3540
+ } \
3541
+ \
3542
+ uint64_t result = vget_lane_u64(vreinterpret_u64_u8(narrowed), 0); \
3543
+ return xsimd::detail::OP(result) / 8; \
3544
+ } \
3545
+ template <class A, class T, detail::enable_sized_t<T, 4> = 0> \
3546
+ XSIMD_INLINE size_t OP(batch_bool<T, A> const& self, requires_arch<neon>) noexcept \
3547
+ { \
3548
+ uint16x4_t narrowed = vmovn_u32(self); \
3549
+ XSIMD_IF_CONSTEXPR(detail::do_swap) \
3550
+ { \
3551
+ narrowed = vrev64_u16(narrowed); \
3552
+ } \
3553
+ \
3554
+ uint64_t result = vget_lane_u64(vreinterpret_u64_u16(narrowed), 0); \
3555
+ return xsimd::detail::OP(result) / 16; \
3556
+ } \
3557
+ template <class A, class T, detail::enable_sized_t<T, 8> = 0> \
3558
+ XSIMD_INLINE size_t OP(batch_bool<T, A> const& self, requires_arch<neon>) noexcept \
3559
+ { \
3560
+ uint32x2_t narrowed = vmovn_u64(self); \
3561
+ XSIMD_IF_CONSTEXPR(detail::do_swap) \
3562
+ { \
3563
+ narrowed = vrev64_u32(narrowed); \
3564
+ } \
3565
+ \
3566
+ uint64_t result = vget_lane_u64(vreinterpret_u64_u32(narrowed), 0); \
3567
+ return xsimd::detail::OP(result) / 32; \
3568
+ }
3569
+
3570
+ WRAP_MASK_OP(countl_zero)
3571
+ WRAP_MASK_OP(countl_one)
3572
+ WRAP_MASK_OP(countr_zero)
3573
+ WRAP_MASK_OP(countr_one)
3574
+
3575
+ #undef WRAP_MASK_OP
3576
+ }
3577
+
3578
+ }
3579
+
3580
+ #endif