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