aboutsummaryrefslogtreecommitdiffstats
path: root/src/utils/simd_32
diff options
context:
space:
mode:
Diffstat (limited to 'src/utils/simd_32')
-rw-r--r--src/utils/simd_32/info.txt18
-rw-r--r--src/utils/simd_32/simd_32.h29
-rw-r--r--src/utils/simd_32/simd_altivec.h178
-rw-r--r--src/utils/simd_32/simd_scalar.h188
-rw-r--r--src/utils/simd_32/simd_sse.h150
5 files changed, 563 insertions, 0 deletions
diff --git a/src/utils/simd_32/info.txt b/src/utils/simd_32/info.txt
new file mode 100644
index 000000000..c72f2a6ed
--- /dev/null
+++ b/src/utils/simd_32/info.txt
@@ -0,0 +1,18 @@
+realname "SIMD"
+
+define SIMD_32
+
+load_on always
+
+<arch>
+pentium-m
+pentium4
+prescott
+amd64
+</arch>
+
+<cc>
+gcc
+icc
+msvc
+</cc>
diff --git a/src/utils/simd_32/simd_32.h b/src/utils/simd_32/simd_32.h
new file mode 100644
index 000000000..d9fac0d3d
--- /dev/null
+++ b/src/utils/simd_32/simd_32.h
@@ -0,0 +1,29 @@
+/**
+* Lightweight wrappers for SIMD operations
+*/
+
+#ifndef BOTAN_SIMD_32_H__
+#define BOTAN_SIMD_32_H__
+
+#include <botan/types.h>
+
+//#define BOTAN_TARGET_CPU_HAS_SSE2
+
+#if defined(BOTAN_TARGET_CPU_HAS_SSE2)
+
+ #include <botan/simd_sse.h>
+ namespace Botan { typedef SIMD_SSE2 SIMD_32; }
+
+#elif defined(BOTAN_TARGET_CPU_HAS_ALTIVEC)
+
+ #include <botan/simd_altivec.h>
+ namespace Botan { typedef SIMD_Altivec SIMD_32; }
+
+#else
+
+ #include <botan/simd_scalar.h>
+ namespace Botan { typedef SIMD_Scalar SIMD_32; }
+
+#endif
+
+#endif
diff --git a/src/utils/simd_32/simd_altivec.h b/src/utils/simd_32/simd_altivec.h
new file mode 100644
index 000000000..d6aaa699d
--- /dev/null
+++ b/src/utils/simd_32/simd_altivec.h
@@ -0,0 +1,178 @@
+/**
+* Altivec SIMD
+*/
+
+#ifndef BOTAN_SIMD_ALTIVEC_H__
+#define BOTAN_SIMD_ALTIVEC_H__
+
+#include <botan/loadstor.h>
+#include <altivec.h>
+#undef vector
+
+namespace Botan {
+
+class SIMD_Altivec
+ {
+ public:
+
+ SIMD_Altivec(const u32bit B[4])
+ {
+ reg = (__vector unsigned int){B[0], B[1], B[2], B[3]};
+ }
+
+ SIMD_Altivec(u32bit B0, u32bit B1, u32bit B2, u32bit B3)
+ {
+ reg = (__vector unsigned int){B0, B1, B2, B3};
+ }
+
+ SIMD_Altivec(u32bit B)
+ {
+ reg = (__vector unsigned int){B, B, B, B};
+ }
+
+ static SIMD_Altivec load_le(const void* in)
+ {
+ const u32bit* in_32 = static_cast<const u32bit*>(in);
+
+ __vector unsigned int R0 = vec_ld(0, in_32);
+ __vector unsigned int R1 = vec_ld(12, in_32);
+
+ __vector unsigned char perm = vec_lvsl(0, in_32);
+
+ perm = vec_xor(perm, vec_splat_u8(3));
+
+ R0 = vec_perm(R0, R1, perm);
+
+ return SIMD_Altivec(R0);
+ }
+
+ static SIMD_Altivec load_be(const void* in)
+ {
+ const u32bit* in_32 = static_cast<const u32bit*>(in);
+
+ __vector unsigned int R0 = vec_ld(0, in_32);
+ __vector unsigned int R1 = vec_ld(12, in_32);
+
+ __vector unsigned char perm = vec_lvsl(0, in_32);
+
+ R0 = vec_perm(R0, R1, perm);
+
+ return SIMD_Altivec(R0);
+ }
+
+ void store_le(byte out[]) const
+ {
+ u32bit* out_32 = reinterpret_cast<u32bit*>(out);
+
+ __vector unsigned char perm = vec_lvsl(0, (int*)0);
+
+ perm = vec_xor(perm, vec_splat_u8(3));
+
+ __vector unsigned int swapped = vec_perm(reg, reg, perm);
+
+ vec_st(swapped, 0, out_32);
+ }
+
+ void store_be(byte out[]) const
+ {
+ u32bit* out_32 = reinterpret_cast<u32bit*>(out);
+ vec_st(reg, 0, out_32);
+ }
+
+ void rotate_left(u32bit rot)
+ {
+ __vector unsigned int rot_vec =
+ (__vector unsigned int){rot, rot, rot, rot};
+
+ reg = vec_rl(reg, rot_vec);
+ }
+
+ void rotate_right(u32bit rot)
+ {
+ rotate_left(32 - rot);
+ }
+
+ void operator+=(const SIMD_Altivec& other)
+ {
+ reg = vec_add(reg, other.reg);
+ }
+
+ SIMD_Altivec operator+(const SIMD_Altivec& other) const
+ {
+ return vec_add(reg, other.reg);
+ }
+
+ void operator-=(const SIMD_Altivec& other)
+ {
+ reg = vec_sub(reg, other.reg);
+ }
+
+ SIMD_Altivec operator-(const SIMD_Altivec& other) const
+ {
+ return vec_sub(reg, other.reg);
+ }
+
+ void operator^=(const SIMD_Altivec& other)
+ {
+ reg = vec_xor(reg, other.reg);
+ }
+
+ SIMD_Altivec operator^(const SIMD_Altivec& other) const
+ {
+ return vec_xor(reg, other.reg);
+ }
+
+ void operator|=(const SIMD_Altivec& other)
+ {
+ reg = vec_or(reg, other.reg);
+ }
+
+ void operator&=(const SIMD_Altivec& other)
+ {
+ reg = vec_and(reg, other.reg);
+ }
+
+ SIMD_Altivec operator<<(u32bit shift) const
+ {
+ __vector unsigned int shift_vec =
+ (__vector unsigned int){shift, shift, shift, shift};
+
+ return vec_sl(reg, shift_vec);
+ }
+
+ SIMD_Altivec operator>>(u32bit shift) const
+ {
+ __vector unsigned int shift_vec =
+ (__vector unsigned int){shift, shift, shift, shift};
+
+ return vec_sr(reg, shift_vec);
+ }
+
+ SIMD_Altivec operator~() const
+ {
+ return vec_nor(reg, reg);
+ }
+
+ static void transpose(SIMD_Altivec& B0, SIMD_Altivec& B1,
+ SIMD_Altivec& B2, SIMD_Altivec& B3)
+ {
+ __vector unsigned int T0 = vec_mergeh(B0.reg, B2.reg);
+ __vector unsigned int T1 = vec_mergel(B0.reg, B2.reg);
+ __vector unsigned int T2 = vec_mergeh(B1.reg, B3.reg);
+ __vector unsigned int T3 = vec_mergel(B1.reg, B3.reg);
+
+ B0.reg = vec_mergeh(T0, T2);
+ B1.reg = vec_mergel(T0, T2);
+ B2.reg = vec_mergeh(T1, T3);
+ B3.reg = vec_mergel(T1, T3);
+ }
+
+ private:
+ SIMD_Altivec(__vector unsigned int input) { reg = input; }
+
+ __vector unsigned int reg;
+ };
+
+}
+
+#endif
diff --git a/src/utils/simd_32/simd_scalar.h b/src/utils/simd_32/simd_scalar.h
new file mode 100644
index 000000000..4b81c183b
--- /dev/null
+++ b/src/utils/simd_32/simd_scalar.h
@@ -0,0 +1,188 @@
+/**
+* Scalar emulation of SIMD operations
+*/
+
+#ifndef BOTAN_SIMD_SCALAR_H__
+#define BOTAN_SIMD_SCALAR_H__
+
+#include <botan/loadstor.h>
+
+namespace Botan {
+
+class SIMD_Scalar
+ {
+ public:
+ SIMD_Scalar(const u32bit B[4])
+ {
+ R0 = B[0];
+ R1 = B[1];
+ R2 = B[2];
+ R3 = B[3];
+ }
+
+ SIMD_Scalar(u32bit B0, u32bit B1, u32bit B2, u32bit B3)
+ {
+ R0 = B0;
+ R1 = B1;
+ R2 = B2;
+ R3 = B3;
+ }
+
+ SIMD_Scalar(u32bit B)
+ {
+ R0 = B;
+ R1 = B;
+ R2 = B;
+ R3 = B;
+ }
+
+ static SIMD_Scalar load_le(const void* in)
+ {
+ const byte* in_b = static_cast<const byte*>(in);
+ return SIMD_Scalar(Botan::load_le<u32bit>(in_b, 0),
+ Botan::load_le<u32bit>(in_b, 1),
+ Botan::load_le<u32bit>(in_b, 2),
+ Botan::load_le<u32bit>(in_b, 3));
+ }
+
+ static SIMD_Scalar load_be(const void* in)
+ {
+ const byte* in_b = static_cast<const byte*>(in);
+ return SIMD_Scalar(Botan::load_be<u32bit>(in_b, 0),
+ Botan::load_be<u32bit>(in_b, 1),
+ Botan::load_be<u32bit>(in_b, 2),
+ Botan::load_be<u32bit>(in_b, 3));
+ }
+
+ void store_le(byte out[]) const
+ {
+ Botan::store_le(out, R0, R1, R2, R3);
+ }
+
+ void store_be(byte out[]) const
+ {
+ Botan::store_be(out, R0, R1, R2, R3);
+ }
+
+ void rotate_left(u32bit rot)
+ {
+ R0 = Botan::rotate_left(R0, rot);
+ R1 = Botan::rotate_left(R1, rot);
+ R2 = Botan::rotate_left(R2, rot);
+ R3 = Botan::rotate_left(R3, rot);
+ }
+
+ void rotate_right(u32bit rot)
+ {
+ R0 = Botan::rotate_right(R0, rot);
+ R1 = Botan::rotate_right(R1, rot);
+ R2 = Botan::rotate_right(R2, rot);
+ R3 = Botan::rotate_right(R3, rot);
+ }
+
+ void operator+=(const SIMD_Scalar& other)
+ {
+ R0 += other.R0;
+ R1 += other.R1;
+ R2 += other.R2;
+ R3 += other.R3;
+ }
+
+ SIMD_Scalar operator+(const SIMD_Scalar& other) const
+ {
+ return SIMD_Scalar(R0 + other.R0,
+ R1 + other.R1,
+ R2 + other.R2,
+ R3 + other.R3);
+ }
+
+ void operator-=(const SIMD_Scalar& other)
+ {
+ R0 -= other.R0;
+ R1 -= other.R1;
+ R2 -= other.R2;
+ R3 -= other.R3;
+ }
+
+ SIMD_Scalar operator-(const SIMD_Scalar& other) const
+ {
+ return SIMD_Scalar(R0 - other.R0,
+ R1 - other.R1,
+ R2 - other.R2,
+ R3 - other.R3);
+ }
+
+ void operator^=(const SIMD_Scalar& other)
+ {
+ R0 ^= other.R0;
+ R1 ^= other.R1;
+ R2 ^= other.R2;
+ R3 ^= other.R3;
+ }
+
+ SIMD_Scalar operator^(const SIMD_Scalar& other) const
+ {
+ return SIMD_Scalar(R0 ^ other.R0,
+ R1 ^ other.R1,
+ R2 ^ other.R2,
+ R3 ^ other.R3);
+ }
+
+ void operator|=(const SIMD_Scalar& other)
+ {
+ R0 |= other.R0;
+ R1 |= other.R1;
+ R2 |= other.R2;
+ R3 |= other.R3;
+ }
+
+ void operator&=(const SIMD_Scalar& other)
+ {
+ R0 &= other.R0;
+ R1 &= other.R1;
+ R2 &= other.R2;
+ R3 &= other.R3;
+ }
+
+ SIMD_Scalar operator<<(u32bit shift) const
+ {
+ return SIMD_Scalar(R0 << shift,
+ R1 << shift,
+ R2 << shift,
+ R3 << shift);
+ }
+
+ SIMD_Scalar operator>>(u32bit shift) const
+ {
+ return SIMD_Scalar(R0 >> shift,
+ R1 >> shift,
+ R2 >> shift,
+ R3 >> shift);
+ }
+
+ SIMD_Scalar operator~() const
+ {
+ return SIMD_Scalar(~R0, ~R1, ~R2, ~R3);
+ }
+
+ static void transpose(SIMD_Scalar& B0, SIMD_Scalar& B1,
+ SIMD_Scalar& B2, SIMD_Scalar& B3)
+ {
+ SIMD_Scalar T0(B0.R0, B1.R0, B2.R0, B3.R0);
+ SIMD_Scalar T1(B0.R1, B1.R1, B2.R1, B3.R1);
+ SIMD_Scalar T2(B0.R2, B1.R2, B2.R2, B3.R2);
+ SIMD_Scalar T3(B0.R3, B1.R3, B2.R3, B3.R3);
+
+ B0 = T0;
+ B1 = T1;
+ B2 = T2;
+ B3 = T3;
+ }
+
+ private:
+ u32bit R0, R1, R2, R3;
+ };
+
+}
+
+#endif
diff --git a/src/utils/simd_32/simd_sse.h b/src/utils/simd_32/simd_sse.h
new file mode 100644
index 000000000..d32ffdc2e
--- /dev/null
+++ b/src/utils/simd_32/simd_sse.h
@@ -0,0 +1,150 @@
+/**
+* Lightweight wrappers for SSE2 intrinsics for 32-bit operations
+*/
+
+#ifndef BOTAN_SIMD_SSE_H__
+#define BOTAN_SIMD_SSE_H__
+
+#include <botan/types.h>
+#include <emmintrin.h>
+
+namespace Botan {
+
+class SIMD_SSE2
+ {
+ public:
+ SIMD_SSE2(const u32bit B[4])
+ {
+ reg = _mm_loadu_si128((const __m128i*)B);
+ }
+
+ SIMD_SSE2(u32bit B0, u32bit B1, u32bit B2, u32bit B3)
+ {
+ reg = _mm_set_epi32(B0, B1, B2, B3);
+ }
+
+ SIMD_SSE2(u32bit B)
+ {
+ reg = _mm_set1_epi32(B);
+ }
+
+ static SIMD_SSE2 load_le(const void* in)
+ {
+ return _mm_loadu_si128((const __m128i*)in);
+ }
+
+ static SIMD_SSE2 load_be(const void* in)
+ {
+ return load_le(in).bswap();
+ }
+
+ void store_le(byte out[]) const
+ {
+ _mm_storeu_si128((__m128i*)out, reg);
+ }
+
+ void store_be(byte out[]) const
+ {
+ bswap().store_le(out);
+ }
+
+ void rotate_left(u32bit rot)
+ {
+ reg = _mm_or_si128(_mm_slli_epi32(reg, rot),
+ _mm_srli_epi32(reg, 32-rot));
+ }
+
+ void rotate_right(u32bit rot)
+ {
+ rotate_left(32 - rot);
+ }
+
+ void operator+=(const SIMD_SSE2& other)
+ {
+ reg = _mm_add_epi32(reg, other.reg);
+ }
+
+ SIMD_SSE2 operator+(const SIMD_SSE2& other) const
+ {
+ return _mm_add_epi32(reg, other.reg);
+ }
+
+ void operator-=(const SIMD_SSE2& other)
+ {
+ reg = _mm_sub_epi32(reg, other.reg);
+ }
+
+ SIMD_SSE2 operator-(const SIMD_SSE2& other) const
+ {
+ return _mm_sub_epi32(reg, other.reg);
+ }
+
+ void operator^=(const SIMD_SSE2& other)
+ {
+ reg = _mm_xor_si128(reg, other.reg);
+ }
+
+ SIMD_SSE2 operator^(const SIMD_SSE2& other) const
+ {
+ return _mm_xor_si128(reg, other.reg);
+ }
+
+ void operator|=(const SIMD_SSE2& other)
+ {
+ reg = _mm_or_si128(reg, other.reg);
+ }
+
+ void operator&=(const SIMD_SSE2& other)
+ {
+ reg = _mm_and_si128(reg, other.reg);
+ }
+
+ SIMD_SSE2 operator<<(u32bit shift) const
+ {
+ return _mm_slli_epi32(reg, shift);
+ }
+
+ SIMD_SSE2 operator>>(u32bit shift) const
+ {
+ return _mm_srli_epi32(reg, shift);
+ }
+
+ SIMD_SSE2 operator~() const
+ {
+ static const __m128i all_ones = _mm_set1_epi32(0xFFFFFFFF);
+ return _mm_xor_si128(reg, all_ones);
+ }
+
+ static void transpose(SIMD_SSE2& B0, SIMD_SSE2& B1,
+ SIMD_SSE2& B2, SIMD_SSE2& B3)
+ {
+ __m128i T0 = _mm_unpacklo_epi32(B0.reg, B1.reg);
+ __m128i T1 = _mm_unpacklo_epi32(B2.reg, B3.reg);
+ __m128i T2 = _mm_unpackhi_epi32(B0.reg, B1.reg);
+ __m128i T3 = _mm_unpackhi_epi32(B2.reg, B3.reg);
+ B0.reg = _mm_unpacklo_epi64(T0, T1);
+ B1.reg = _mm_unpackhi_epi64(T0, T1);
+ B2.reg = _mm_unpacklo_epi64(T2, T3);
+ B3.reg = _mm_unpackhi_epi64(T2, T3);
+ }
+
+ private:
+ SIMD_SSE2(__m128i in) { reg = in; }
+
+ SIMD_SSE2 bswap() const
+ {
+ __m128i T = reg;
+
+ T = _mm_shufflehi_epi16(T, _MM_SHUFFLE(2, 3, 0, 1));
+ T = _mm_shufflelo_epi16(T, _MM_SHUFFLE(2, 3, 0, 1));
+
+ return _mm_or_si128(_mm_srli_epi16(T, 8),
+ _mm_slli_epi16(T, 8));
+ }
+
+ __m128i reg;
+ };
+
+}
+
+#endif