aboutsummaryrefslogtreecommitdiffstats
path: root/lib/simd/simd_scalar/simd_scalar.h
diff options
context:
space:
mode:
Diffstat (limited to 'lib/simd/simd_scalar/simd_scalar.h')
-rw-r--r--lib/simd/simd_scalar/simd_scalar.h215
1 files changed, 215 insertions, 0 deletions
diff --git a/lib/simd/simd_scalar/simd_scalar.h b/lib/simd/simd_scalar/simd_scalar.h
new file mode 100644
index 000000000..55dd26d6f
--- /dev/null
+++ b/lib/simd/simd_scalar/simd_scalar.h
@@ -0,0 +1,215 @@
+/*
+* Scalar emulation of SIMD
+* (C) 2009,2013 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#ifndef BOTAN_SIMD_SCALAR_H__
+#define BOTAN_SIMD_SCALAR_H__
+
+#include <botan/loadstor.h>
+#include <botan/bswap.h>
+
+namespace Botan {
+
+/**
+* Fake SIMD, using plain scalar operations
+* Often still faster than iterative on superscalar machines
+*/
+template<typename T, size_t N>
+class SIMD_Scalar
+ {
+ public:
+ static bool enabled() { return true; }
+
+ static size_t size() { return N; }
+
+ SIMD_Scalar() { /* uninitialized */ }
+
+ SIMD_Scalar(const T B[N])
+ {
+ for(size_t i = 0; i != size(); ++i)
+ m_v[i] = B[i];
+ }
+
+ SIMD_Scalar(T B)
+ {
+ for(size_t i = 0; i != size(); ++i)
+ m_v[i] = B;
+ }
+
+ static SIMD_Scalar<T,N> load_le(const void* in)
+ {
+ SIMD_Scalar<T,N> out;
+ const byte* in_b = static_cast<const byte*>(in);
+
+ for(size_t i = 0; i != size(); ++i)
+ out.m_v[i] = Botan::load_le<T>(in_b, i);
+
+ return out;
+ }
+
+ static SIMD_Scalar<T,N> load_be(const void* in)
+ {
+ SIMD_Scalar<T,N> out;
+ const byte* in_b = static_cast<const byte*>(in);
+
+ for(size_t i = 0; i != size(); ++i)
+ out.m_v[i] = Botan::load_be<T>(in_b, i);
+
+ return out;
+ }
+
+ void store_le(byte out[]) const
+ {
+ for(size_t i = 0; i != size(); ++i)
+ Botan::store_le(m_v[i], out + i*sizeof(T));
+ }
+
+ void store_be(byte out[]) const
+ {
+ for(size_t i = 0; i != size(); ++i)
+ Botan::store_be(m_v[i], out + i*sizeof(T));
+ }
+
+ void rotate_left(size_t rot)
+ {
+ for(size_t i = 0; i != size(); ++i)
+ m_v[i] = Botan::rotate_left(m_v[i], rot);
+ }
+
+ void rotate_right(size_t rot)
+ {
+ for(size_t i = 0; i != size(); ++i)
+ m_v[i] = Botan::rotate_right(m_v[i], rot);
+ }
+
+ void operator+=(const SIMD_Scalar<T,N>& other)
+ {
+ for(size_t i = 0; i != size(); ++i)
+ m_v[i] += other.m_v[i];
+ }
+
+ void operator-=(const SIMD_Scalar<T,N>& other)
+ {
+ for(size_t i = 0; i != size(); ++i)
+ m_v[i] -= other.m_v[i];
+ }
+
+ SIMD_Scalar<T,N> operator+(const SIMD_Scalar<T,N>& other) const
+ {
+ SIMD_Scalar<T,N> out = *this;
+ out += other;
+ return out;
+ }
+
+ SIMD_Scalar<T,N> operator-(const SIMD_Scalar<T,N>& other) const
+ {
+ SIMD_Scalar<T,N> out = *this;
+ out -= other;
+ return out;
+ }
+
+ void operator^=(const SIMD_Scalar<T,N>& other)
+ {
+ for(size_t i = 0; i != size(); ++i)
+ m_v[i] ^= other.m_v[i];
+ }
+
+ SIMD_Scalar<T,N> operator^(const SIMD_Scalar<T,N>& other) const
+ {
+ SIMD_Scalar<T,N> out = *this;
+ out ^= other;
+ return out;
+ }
+
+ void operator|=(const SIMD_Scalar<T,N>& other)
+ {
+ for(size_t i = 0; i != size(); ++i)
+ m_v[i] |= other.m_v[i];
+ }
+
+ void operator&=(const SIMD_Scalar<T,N>& other)
+ {
+ for(size_t i = 0; i != size(); ++i)
+ m_v[i] &= other.m_v[i];
+ }
+
+ SIMD_Scalar<T,N> operator&(const SIMD_Scalar<T,N>& other)
+ {
+ SIMD_Scalar<T,N> out = *this;
+ out &= other;
+ return out;
+ }
+
+ SIMD_Scalar<T,N> operator<<(size_t shift) const
+ {
+ SIMD_Scalar<T,N> out = *this;
+ for(size_t i = 0; i != size(); ++i)
+ out.m_v[i] <<= shift;
+ return out;
+ }
+
+ SIMD_Scalar<T,N> operator>>(size_t shift) const
+ {
+ SIMD_Scalar<T,N> out = *this;
+ for(size_t i = 0; i != size(); ++i)
+ out.m_v[i] >>= shift;
+ return out;
+ }
+
+ SIMD_Scalar<T,N> operator~() const
+ {
+ SIMD_Scalar<T,N> out = *this;
+ for(size_t i = 0; i != size(); ++i)
+ out.m_v[i] = ~out.m_v[i];
+ return out;
+ }
+
+ // (~reg) & other
+ SIMD_Scalar<T,N> andc(const SIMD_Scalar<T,N>& other)
+ {
+ SIMD_Scalar<T,N> out;
+ for(size_t i = 0; i != size(); ++i)
+ out.m_v[i] = (~m_v[i]) & other.m_v[i];
+ return out;
+ }
+
+ SIMD_Scalar<T,N> bswap() const
+ {
+ SIMD_Scalar<T,N> out;
+ for(size_t i = 0; i != size(); ++i)
+ out.m_v[i] = reverse_bytes(m_v[i]);
+ return out;
+ }
+
+ static void transpose(SIMD_Scalar<T,N>& B0, SIMD_Scalar<T,N>& B1,
+ SIMD_Scalar<T,N>& B2, SIMD_Scalar<T,N>& B3)
+ {
+ static_assert(N == 4, "4x4 transpose");
+ SIMD_Scalar<T,N> T0({B0.m_v[0], B1.m_v[0], B2.m_v[0], B3.m_v[0]});
+ SIMD_Scalar<T,N> T1({B0.m_v[1], B1.m_v[1], B2.m_v[1], B3.m_v[1]});
+ SIMD_Scalar<T,N> T2({B0.m_v[2], B1.m_v[2], B2.m_v[2], B3.m_v[2]});
+ SIMD_Scalar<T,N> T3({B0.m_v[3], B1.m_v[3], B2.m_v[3], B3.m_v[3]});
+
+ B0 = T0;
+ B1 = T1;
+ B2 = T2;
+ B3 = T3;
+ }
+
+ private:
+ SIMD_Scalar(std::initializer_list<T> B)
+ {
+ size_t i = 0;
+ for(auto v = B.begin(); v != B.end(); ++v)
+ m_v[i++] = *v;
+ }
+
+ T m_v[N];
+ };
+
+}
+
+#endif