Botan
1.11.15
|
00001 /* 00002 * Lightweight wrappers around AltiVec for 32-bit operations 00003 * (C) 2009 Jack Lloyd 00004 * 00005 * Botan is released under the Simplified BSD License (see license.txt) 00006 */ 00007 00008 #ifndef BOTAN_SIMD_ALTIVEC_H__ 00009 #define BOTAN_SIMD_ALTIVEC_H__ 00010 00011 #if defined(BOTAN_TARGET_SUPPORTS_ALTIVEC) 00012 00013 #include <botan/loadstor.h> 00014 #include <botan/cpuid.h> 00015 00016 #include <altivec.h> 00017 #undef vector 00018 #undef bool 00019 00020 namespace Botan { 00021 00022 class SIMD_Altivec 00023 { 00024 public: 00025 static bool enabled() { return CPUID::has_altivec(); } 00026 00027 SIMD_Altivec(const u32bit B[4]) 00028 { 00029 m_reg = (__vector unsigned int){B[0], B[1], B[2], B[3]}; 00030 } 00031 00032 SIMD_Altivec(u32bit B0, u32bit B1, u32bit B2, u32bit B3) 00033 { 00034 m_reg = (__vector unsigned int){B0, B1, B2, B3}; 00035 } 00036 00037 SIMD_Altivec(u32bit B) 00038 { 00039 m_reg = (__vector unsigned int){B, B, B, B}; 00040 } 00041 00042 static SIMD_Altivec load_le(const void* in) 00043 { 00044 const u32bit* in_32 = static_cast<const u32bit*>(in); 00045 00046 __vector unsigned int R0 = vec_ld(0, in_32); 00047 __vector unsigned int R1 = vec_ld(12, in_32); 00048 00049 __vector unsigned char perm = vec_lvsl(0, in_32); 00050 00051 perm = vec_xor(perm, vec_splat_u8(3)); 00052 00053 R0 = vec_perm(R0, R1, perm); 00054 00055 return SIMD_Altivec(R0); 00056 } 00057 00058 static SIMD_Altivec load_be(const void* in) 00059 { 00060 const u32bit* in_32 = static_cast<const u32bit*>(in); 00061 00062 __vector unsigned int R0 = vec_ld(0, in_32); 00063 __vector unsigned int R1 = vec_ld(12, in_32); 00064 00065 __vector unsigned char perm = vec_lvsl(0, in_32); 00066 00067 R0 = vec_perm(R0, R1, perm); 00068 00069 return SIMD_Altivec(R0); 00070 } 00071 00072 void store_le(byte out[]) const 00073 { 00074 __vector unsigned char perm = vec_lvsl(0, (u32bit*)0); 00075 00076 perm = vec_xor(perm, vec_splat_u8(3)); 00077 00078 union { 00079 __vector unsigned int V; 00080 u32bit R[4]; 00081 } vec; 00082 00083 vec.V = vec_perm(m_reg, m_reg, perm); 00084 00085 Botan::store_be(out, vec.R[0], vec.R[1], vec.R[2], vec.R[3]); 00086 } 00087 00088 void store_be(byte out[]) const 00089 { 00090 union { 00091 __vector unsigned int V; 00092 u32bit R[4]; 00093 } vec; 00094 00095 vec.V = m_reg; 00096 00097 Botan::store_be(out, vec.R[0], vec.R[1], vec.R[2], vec.R[3]); 00098 } 00099 00100 void rotate_left(size_t rot) 00101 { 00102 const unsigned int r = static_cast<unsigned int>(rot); 00103 m_reg = vec_rl(m_reg, (__vector unsigned int){r, r, r, r}); 00104 } 00105 00106 void rotate_right(size_t rot) 00107 { 00108 rotate_left(32 - rot); 00109 } 00110 00111 void operator+=(const SIMD_Altivec& other) 00112 { 00113 m_reg = vec_add(m_reg, other.m_reg); 00114 } 00115 00116 SIMD_Altivec operator+(const SIMD_Altivec& other) const 00117 { 00118 return vec_add(m_reg, other.m_reg); 00119 } 00120 00121 void operator-=(const SIMD_Altivec& other) 00122 { 00123 m_reg = vec_sub(m_reg, other.m_reg); 00124 } 00125 00126 SIMD_Altivec operator-(const SIMD_Altivec& other) const 00127 { 00128 return vec_sub(m_reg, other.m_reg); 00129 } 00130 00131 void operator^=(const SIMD_Altivec& other) 00132 { 00133 m_reg = vec_xor(m_reg, other.m_reg); 00134 } 00135 00136 SIMD_Altivec operator^(const SIMD_Altivec& other) const 00137 { 00138 return vec_xor(m_reg, other.m_reg); 00139 } 00140 00141 void operator|=(const SIMD_Altivec& other) 00142 { 00143 m_reg = vec_or(m_reg, other.m_reg); 00144 } 00145 00146 SIMD_Altivec operator&(const SIMD_Altivec& other) 00147 { 00148 return vec_and(m_reg, other.m_reg); 00149 } 00150 00151 void operator&=(const SIMD_Altivec& other) 00152 { 00153 m_reg = vec_and(m_reg, other.m_reg); 00154 } 00155 00156 SIMD_Altivec operator<<(size_t shift) const 00157 { 00158 const unsigned int s = static_cast<unsigned int>(shift); 00159 return vec_sl(m_reg, (__vector unsigned int){s, s, s, s}); 00160 } 00161 00162 SIMD_Altivec operator>>(size_t shift) const 00163 { 00164 const unsigned int s = static_cast<unsigned int>(shift); 00165 return vec_sr(m_reg, (__vector unsigned int){s, s, s, s}); 00166 } 00167 00168 SIMD_Altivec operator~() const 00169 { 00170 return vec_nor(m_reg, m_reg); 00171 } 00172 00173 SIMD_Altivec andc(const SIMD_Altivec& other) 00174 { 00175 /* 00176 AltiVec does arg1 & ~arg2 rather than SSE's ~arg1 & arg2 00177 so swap the arguments 00178 */ 00179 return vec_andc(other.m_reg, m_reg); 00180 } 00181 00182 SIMD_Altivec bswap() const 00183 { 00184 __vector unsigned char perm = vec_lvsl(0, (u32bit*)0); 00185 00186 perm = vec_xor(perm, vec_splat_u8(3)); 00187 00188 return SIMD_Altivec(vec_perm(m_reg, m_reg, perm)); 00189 } 00190 00191 static void transpose(SIMD_Altivec& B0, SIMD_Altivec& B1, 00192 SIMD_Altivec& B2, SIMD_Altivec& B3) 00193 { 00194 __vector unsigned int T0 = vec_mergeh(B0.m_reg, B2.m_reg); 00195 __vector unsigned int T1 = vec_mergel(B0.m_reg, B2.m_reg); 00196 __vector unsigned int T2 = vec_mergeh(B1.m_reg, B3.m_reg); 00197 __vector unsigned int T3 = vec_mergel(B1.m_reg, B3.m_reg); 00198 00199 B0.m_reg = vec_mergeh(T0, T2); 00200 B1.m_reg = vec_mergel(T0, T2); 00201 B2.m_reg = vec_mergeh(T1, T3); 00202 B3.m_reg = vec_mergel(T1, T3); 00203 } 00204 00205 private: 00206 SIMD_Altivec(__vector unsigned int input) { m_reg = input; } 00207 00208 __vector unsigned int m_reg; 00209 }; 00210 00211 } 00212 00213 #endif 00214 00215 #endif