diff options
Diffstat (limited to 'src/utils/simd_32')
-rw-r--r-- | src/utils/simd_32/info.txt | 16 | ||||
-rw-r--r-- | src/utils/simd_32/simd_32.h | 32 | ||||
-rw-r--r-- | src/utils/simd_32/simd_altivec.h | 202 | ||||
-rw-r--r-- | src/utils/simd_32/simd_scalar.h | 202 | ||||
-rw-r--r-- | src/utils/simd_32/simd_sse.h | 156 |
5 files changed, 608 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..64707c1e4 --- /dev/null +++ b/src/utils/simd_32/info.txt @@ -0,0 +1,16 @@ +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..be426efd6 --- /dev/null +++ b/src/utils/simd_32/simd_32.h @@ -0,0 +1,32 @@ +/** +* Lightweight wrappers for SIMD operations +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#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..e1aa62002 --- /dev/null +++ b/src/utils/simd_32/simd_altivec.h @@ -0,0 +1,202 @@ +/** +* Lightweight wrappers around AltiVec for 32-bit operations +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_SIMD_ALTIVEC_H__ +#define BOTAN_SIMD_ALTIVEC_H__ + +#include <botan/loadstor.h> +#include <botan/cpuid.h> + +#include <altivec.h> +#undef vector + +namespace Botan { + +class SIMD_Altivec + { + public: + bool enabled() const { return CPUID::has_altivec(); } + + 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 + { + __vector unsigned char perm = vec_lvsl(0, (u32bit*)0); + + perm = vec_xor(perm, vec_splat_u8(3)); + + union { + __vector unsigned int V; + u32bit R[4]; + } vec; + + vec.V = vec_perm(reg, reg, perm); + + Botan::store_be(out, vec.R[0], vec.R[1], vec.R[2], vec.R[3]); + } + + void store_be(byte out[]) const + { + union { + __vector unsigned int V; + u32bit R[4]; + } vec; + + vec.V = reg; + + Botan::store_be(out, vec.R[0], vec.R[1], vec.R[2], vec.R[3]); + } + + 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); + } + + SIMD_Altivec bswap() const + { + __vector unsigned char perm = vec_lvsl(0, (u32bit*)0); + + perm = vec_xor(perm, vec_splat_u8(3)); + + return SIMD_Altivec(vec_perm(reg, reg, perm)); + } + + 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..5fc20b462 --- /dev/null +++ b/src/utils/simd_32/simd_scalar.h @@ -0,0 +1,202 @@ +/** +* Scalar emulation of SIMD 32-bit operations +* (C) 2009 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 { + +class SIMD_Scalar + { + public: + bool enabled() const { return true; } + + 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); + } + + SIMD_Scalar bswap() const + { + return SIMD_Scalar(reverse_bytes(R0), + reverse_bytes(R1), + reverse_bytes(R2), + reverse_bytes(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..c45d8032f --- /dev/null +++ b/src/utils/simd_32/simd_sse.h @@ -0,0 +1,156 @@ +/** +* Lightweight wrappers for SSE2 intrinsics for 32-bit operations +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_SIMD_SSE_H__ +#define BOTAN_SIMD_SSE_H__ + +#include <botan/cpuid.h> + +#include <emmintrin.h> + +namespace Botan { + +class SIMD_SSE2 + { + public: + bool enabled() const { return CPUID::has_sse2(); } + + 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); + } + + 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)); + } + + 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; } + + __m128i reg; + }; + +} + +#endif |