1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#![feature(concat_idents, exclusive_range_pattern)]
#![cfg_attr(target_feature = "sse", feature(stdarch_x86_mm_shuffle))]
#![cfg_attr(target_arch = "wasm32", feature(simd_wasm64))]
#![cfg_attr(not(feature = "use_std"), no_std)]

macro_rules! flat_mod {
    ($($i:ident),+) => {
        $(
            mod $i;
            pub use $i::*;
        )*
    };
}

macro_rules! import {
    ($($i:ident),+) => {
        cfg_if::cfg_if! {
            if #[cfg(feature = "force_naive")] {
                $(pub use crate::naive::$i;)*
            } else if #[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "sse"))] {
                $(pub use crate::x86::$i;)*
            } else if #[cfg(all(any(target_arch = "arm", target_arch = "aarch64"), target_feature = "neon"))] {
                $(pub use crate::arm::$i;)*
            } else if #[cfg(all(target_arch = "wasm32", target_feature = "simd128"))] {
                $(pub use crate::wasm::$i;)*
            } else {
                $(pub use crate::naive::$i;)*
            }
        }
    };
}

include!("composite.rs");

#[cfg(feature = "random")]
include!("generics/random.rs");

#[cfg(feature = "serialize")]
include!("generics/serialize.rs");

cfg_if::cfg_if! {
    if #[cfg(feature = "force_naive")] {
        mod naive;
    } else if #[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "sse"))] {
        mod x86;
        include!("generics/float.rs");
    } else if #[cfg(all(any(target_arch = "arm", target_arch = "aarch64"), target_feature = "neon"))] {
        mod arm;
        include!("generics/float.rs");
    } else if #[cfg(all(target_arch = "wasm32", target_feature = "simd128"))] {
        mod wasm;
        include!("generics/float.rs");
    } else {
        mod naive;
    }
}

/// Floating-point vectors
pub mod float {
    /// Single-precision floating point vectors
    pub mod single {
        import!(f32x2, f32x4, f32x6, f32x8, f32x10, f32x12, f32x14, f32x16);
    }

    /// Double-precision floating point vectors
    pub mod double {
        import!(f64x2, f64x4, f64x6, f64x8, f64x10, f64x12, f64x14, f64x16);
    }
}

/// Check current implementation
pub enum LlmlImpl {
    /// x86/x86_64 SSE (128-bit) implementation
    SSE,

    /// x86/x86_64 AVX (128-bit to 256-bit) implementation
    AVX,

    /// arm/aarch64 NEON (64-bit to 128-bit) implementation
    NEON,

    /// WASM32 SIMD128 proposal (128-bit) implementation
    WASM,

    /// Naive implementation with arrays. Useful as a backup if no other method is available
    NAIVE,
}

impl LlmlImpl {
    pub const CURRENT: Self = current_impl();

    #[inline]
    pub const fn is_64bit(&self) -> bool {
        matches!(self, LlmlImpl::NEON)
    }

    #[inline]
    pub const fn is_128bit(&self) -> bool {
        match self {
            LlmlImpl::NAIVE => false,
            _ => true,
        }
    }

    #[inline]
    pub const fn is_256bit(&self) -> bool {
        matches!(self, LlmlImpl::AVX)
    }
}

#[inline]
pub const fn current_impl() -> LlmlImpl {
    cfg_if::cfg_if! {
        if #[cfg(feature = "force_naive")] {
            LlmlImpl::NAIVE
        } else if #[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "sse"))] {
            #[cfg(all(feature = "use_avx", target_feature = "avx"))]
            return LlmlImpl::AVX;
            #[cfg(not(all(feature = "use_avx", target_feature = "avx")))]
            LlmlImpl::SSE
        } else if #[cfg(all(any(target_arch = "arm", target_arch = "aarch64"), target_feature = "neon"))] {
            LlmlImpl::NEON
        } else if #[cfg(all(target_arch = "wasm32", target_feature = "simd128"))] {
            LlmlImpl::WASM
        } else {
            LlmlImpl::NAIVE
        }
    }
}