Botan
1.11.15
|
00001 /* 00002 * Scalar emulation of SIMD 00003 * (C) 2009,2013 Jack Lloyd 00004 * 00005 * Botan is released under the Simplified BSD License (see license.txt) 00006 */ 00007 00008 #ifndef BOTAN_SIMD_SCALAR_H__ 00009 #define BOTAN_SIMD_SCALAR_H__ 00010 00011 #include <botan/loadstor.h> 00012 #include <botan/bswap.h> 00013 00014 namespace Botan { 00015 00016 /** 00017 * Fake SIMD, using plain scalar operations 00018 * Often still faster than iterative on superscalar machines 00019 */ 00020 template<typename T, size_t N> 00021 class SIMD_Scalar 00022 { 00023 public: 00024 static bool enabled() { return true; } 00025 00026 static size_t size() { return N; } 00027 00028 SIMD_Scalar() { /* uninitialized */ } 00029 00030 SIMD_Scalar(const T B[N]) 00031 { 00032 for(size_t i = 0; i != size(); ++i) 00033 m_v[i] = B[i]; 00034 } 00035 00036 SIMD_Scalar(T B) 00037 { 00038 for(size_t i = 0; i != size(); ++i) 00039 m_v[i] = B; 00040 } 00041 00042 static SIMD_Scalar<T,N> load_le(const void* in) 00043 { 00044 SIMD_Scalar<T,N> out; 00045 const byte* in_b = static_cast<const byte*>(in); 00046 00047 for(size_t i = 0; i != size(); ++i) 00048 out.m_v[i] = Botan::load_le<T>(in_b, i); 00049 00050 return out; 00051 } 00052 00053 static SIMD_Scalar<T,N> load_be(const void* in) 00054 { 00055 SIMD_Scalar<T,N> out; 00056 const byte* in_b = static_cast<const byte*>(in); 00057 00058 for(size_t i = 0; i != size(); ++i) 00059 out.m_v[i] = Botan::load_be<T>(in_b, i); 00060 00061 return out; 00062 } 00063 00064 void store_le(byte out[]) const 00065 { 00066 for(size_t i = 0; i != size(); ++i) 00067 Botan::store_le(m_v[i], out + i*sizeof(T)); 00068 } 00069 00070 void store_be(byte out[]) const 00071 { 00072 for(size_t i = 0; i != size(); ++i) 00073 Botan::store_be(m_v[i], out + i*sizeof(T)); 00074 } 00075 00076 void rotate_left(size_t rot) 00077 { 00078 for(size_t i = 0; i != size(); ++i) 00079 m_v[i] = Botan::rotate_left(m_v[i], rot); 00080 } 00081 00082 void rotate_right(size_t rot) 00083 { 00084 for(size_t i = 0; i != size(); ++i) 00085 m_v[i] = Botan::rotate_right(m_v[i], rot); 00086 } 00087 00088 void operator+=(const SIMD_Scalar<T,N>& other) 00089 { 00090 for(size_t i = 0; i != size(); ++i) 00091 m_v[i] += other.m_v[i]; 00092 } 00093 00094 void operator-=(const SIMD_Scalar<T,N>& other) 00095 { 00096 for(size_t i = 0; i != size(); ++i) 00097 m_v[i] -= other.m_v[i]; 00098 } 00099 00100 SIMD_Scalar<T,N> operator+(const SIMD_Scalar<T,N>& other) const 00101 { 00102 SIMD_Scalar<T,N> out = *this; 00103 out += other; 00104 return out; 00105 } 00106 00107 SIMD_Scalar<T,N> operator-(const SIMD_Scalar<T,N>& other) const 00108 { 00109 SIMD_Scalar<T,N> out = *this; 00110 out -= other; 00111 return out; 00112 } 00113 00114 void operator^=(const SIMD_Scalar<T,N>& other) 00115 { 00116 for(size_t i = 0; i != size(); ++i) 00117 m_v[i] ^= other.m_v[i]; 00118 } 00119 00120 SIMD_Scalar<T,N> operator^(const SIMD_Scalar<T,N>& other) const 00121 { 00122 SIMD_Scalar<T,N> out = *this; 00123 out ^= other; 00124 return out; 00125 } 00126 00127 void operator|=(const SIMD_Scalar<T,N>& other) 00128 { 00129 for(size_t i = 0; i != size(); ++i) 00130 m_v[i] |= other.m_v[i]; 00131 } 00132 00133 void operator&=(const SIMD_Scalar<T,N>& other) 00134 { 00135 for(size_t i = 0; i != size(); ++i) 00136 m_v[i] &= other.m_v[i]; 00137 } 00138 00139 SIMD_Scalar<T,N> operator&(const SIMD_Scalar<T,N>& other) 00140 { 00141 SIMD_Scalar<T,N> out = *this; 00142 out &= other; 00143 return out; 00144 } 00145 00146 SIMD_Scalar<T,N> operator<<(size_t shift) const 00147 { 00148 SIMD_Scalar<T,N> out = *this; 00149 for(size_t i = 0; i != size(); ++i) 00150 out.m_v[i] <<= shift; 00151 return out; 00152 } 00153 00154 SIMD_Scalar<T,N> operator>>(size_t shift) const 00155 { 00156 SIMD_Scalar<T,N> out = *this; 00157 for(size_t i = 0; i != size(); ++i) 00158 out.m_v[i] >>= shift; 00159 return out; 00160 } 00161 00162 SIMD_Scalar<T,N> operator~() const 00163 { 00164 SIMD_Scalar<T,N> out = *this; 00165 for(size_t i = 0; i != size(); ++i) 00166 out.m_v[i] = ~out.m_v[i]; 00167 return out; 00168 } 00169 00170 // (~reg) & other 00171 SIMD_Scalar<T,N> andc(const SIMD_Scalar<T,N>& other) 00172 { 00173 SIMD_Scalar<T,N> out; 00174 for(size_t i = 0; i != size(); ++i) 00175 out.m_v[i] = (~m_v[i]) & other.m_v[i]; 00176 return out; 00177 } 00178 00179 SIMD_Scalar<T,N> bswap() const 00180 { 00181 SIMD_Scalar<T,N> out; 00182 for(size_t i = 0; i != size(); ++i) 00183 out.m_v[i] = reverse_bytes(m_v[i]); 00184 return out; 00185 } 00186 00187 static void transpose(SIMD_Scalar<T,N>& B0, SIMD_Scalar<T,N>& B1, 00188 SIMD_Scalar<T,N>& B2, SIMD_Scalar<T,N>& B3) 00189 { 00190 static_assert(N == 4, "4x4 transpose"); 00191 SIMD_Scalar<T,N> T0({B0.m_v[0], B1.m_v[0], B2.m_v[0], B3.m_v[0]}); 00192 SIMD_Scalar<T,N> T1({B0.m_v[1], B1.m_v[1], B2.m_v[1], B3.m_v[1]}); 00193 SIMD_Scalar<T,N> T2({B0.m_v[2], B1.m_v[2], B2.m_v[2], B3.m_v[2]}); 00194 SIMD_Scalar<T,N> T3({B0.m_v[3], B1.m_v[3], B2.m_v[3], B3.m_v[3]}); 00195 00196 B0 = T0; 00197 B1 = T1; 00198 B2 = T2; 00199 B3 = T3; 00200 } 00201 00202 private: 00203 SIMD_Scalar(std::initializer_list<T> B) 00204 { 00205 size_t i = 0; 00206 for(auto v = B.begin(); v != B.end(); ++v) 00207 m_v[i++] = *v; 00208 } 00209 00210 T m_v[N]; 00211 }; 00212 00213 } 00214 00215 #endif