1 /** 2 * Scalar emulation of SIMD 3 * 4 * Copyright: 5 * (C) 2009,2013 Jack Lloyd 6 * (C) 2014-2015 Etienne Cimon 7 * 8 * License: 9 * Botan is released under the Simplified BSD License (see LICENSE.md) 10 */ 11 module botan.simd.simd_scalar; 12 13 import botan.constants; 14 static if (BOTAN_HAS_SIMD_SCALAR): 15 import botan.utils.loadstor; 16 import botan.utils.bswap; 17 import botan.utils.rotate; 18 19 /** 20 * Fake SIMD, using plain scalar operations 21 * Often still faster than iterative on superscalar machines 22 */ 23 struct SIMDScalar(T, size_t N) 24 { 25 public: 26 static bool enabled() { return true; } 27 28 static size_t size() { return N; } 29 30 this(in T[N] B) 31 { 32 for (size_t i = 0; i != size(); ++i) 33 m_v[i] = B[i]; 34 } 35 36 this(T B) 37 { 38 for (size_t i = 0; i != size(); ++i) 39 m_v[i] = B; 40 } 41 42 static SIMDScalar!(T, N) loadLittleEndian(in void* input) 43 { 44 SIMDScalar!(T, N) output; 45 const(ubyte)* in_b = cast(const(ubyte)*)(input); 46 47 for (size_t i = 0; i != size(); ++i) 48 output.m_v[i] = .loadLittleEndian!T(in_b, i); 49 50 return output; 51 } 52 53 static SIMDScalar!(T, N) loadBigEndian(in void* input) 54 { 55 SIMDScalar!(T, N) output; 56 const(ubyte)* in_b = cast(const(ubyte)*)(input); 57 58 for (size_t i = 0; i != size(); ++i) 59 output.m_v[i] = .loadBigEndian!T(in_b, i); 60 61 return output; 62 } 63 64 void storeLittleEndian(ubyte* output) 65 { 66 for (size_t i = 0; i != size(); ++i) 67 .storeLittleEndian(m_v[i], output + i*T.sizeof); 68 } 69 70 void storeBigEndian(ubyte* output) 71 { 72 for (size_t i = 0; i != size(); ++i) 73 .storeBigEndian(m_v[i], output + i*T.sizeof); 74 } 75 76 void rotateLeft(int rot)() 77 { 78 for (size_t i = 0; i != size(); ++i) 79 m_v[i] = .rotateLeft(m_v[i], rot); 80 } 81 82 void rotateRight(int rot)() 83 { 84 for (size_t i = 0; i != size(); ++i) 85 m_v[i] = .rotateRight(m_v[i], rot); 86 } 87 88 void opOpAssign(string op)(in SIMDScalar!(T, N) other) 89 if (op == "+") 90 { 91 for (size_t i = 0; i != size(); ++i) 92 m_v[i] += other.m_v[i]; 93 } 94 95 void opOpAssign(string op)(in SIMDScalar!(T, N) other) 96 if (op == "-") 97 { 98 for (size_t i = 0; i != size(); ++i) 99 m_v[i] -= other.m_v[i]; 100 } 101 102 SIMDScalar!(T, N) opBinary(string op)(in SIMDScalar!(T, N) other) 103 if (op == "+") 104 { 105 this += other; 106 return this; 107 } 108 109 SIMDScalar!(T, N) opBinary(string op)(in SIMDScalar!(T, N) other) 110 if (op == "-") 111 { 112 this -= other; 113 return this; 114 } 115 116 void opOpAssign(string op)(in SIMDScalar!(T, N) other) 117 if (op == "^") 118 { 119 for (size_t i = 0; i != size(); ++i) 120 m_v[i] ^= other.m_v[i]; 121 } 122 123 SIMDScalar!(T, N) opBinary(string op)(in SIMDScalar!(T, N) other) 124 if (op == "^") 125 { 126 this ^= other; 127 return this; 128 } 129 130 void opOpAssign(string op)(in SIMDScalar!(T, N) other) 131 if (op == "|") 132 { 133 for (size_t i = 0; i != size(); ++i) 134 m_v[i] |= other.m_v[i]; 135 } 136 137 void opOpAssign(string op)(in SIMDScalar!(T, N) other) 138 if (op == "&") 139 { 140 for (size_t i = 0; i != size(); ++i) 141 m_v[i] &= other.m_v[i]; 142 } 143 144 SIMDScalar!(T, N) opBinary(string op)(in SIMDScalar!(T, N) other) 145 if (op == "&") 146 { 147 SIMDScalar!(T, N) ret; 148 ret &= other; 149 return ret; 150 } 151 152 SIMDScalar!(T, N) lshift(size_t shift)() 153 { 154 SIMDScalar!(T, N) ret; 155 ret.m_v = m_v; 156 for (size_t i = 0; i != size(); ++i) 157 ret.m_v[i] <<= shift; 158 return ret; 159 } 160 161 SIMDScalar!(T, N) rshift(size_t shift)() 162 { 163 SIMDScalar!(T, N) ret; 164 ret.m_v = m_v; 165 for (size_t i = 0; i != size(); ++i) 166 ret.m_v[i] >>= shift; 167 return ret; 168 } 169 170 SIMDScalar!(T, N) opUnary(string op)() 171 if (op == "~") 172 { 173 SIMDScalar!(T, N) ret; 174 for (size_t i = 0; i != size(); ++i) 175 ret.m_v[i] = ~m_v[i]; 176 return ret; 177 } 178 179 // (~reg) & other 180 SIMDScalar!(T, N) andc(in SIMDScalar!(T, N) other) 181 { 182 SIMDScalar!(T, N) ret; 183 for (size_t i = 0; i != size(); ++i) 184 ret.m_v[i] = (~m_v[i]) & other.m_v[i]; 185 return ret; 186 } 187 188 SIMDScalar!(T, N) bswap() 189 { 190 SIMDScalar!(T, N) ret; 191 for (size_t i = 0; i != size(); ++i) 192 ret.m_v[i] = reverseBytes(m_v[i]); 193 return ret; 194 } 195 196 static void transpose(ref SIMDScalar!(T, N) B0, ref SIMDScalar!(T, N) B1, 197 ref SIMDScalar!(T, N) B2, ref SIMDScalar!(T, N) B3) 198 { 199 static assert(N == 4, "4x4 transpose"); 200 SIMDScalar!(T, N) T0 = SIMDScalar!(T, N)([B0.m_v[0], B1.m_v[0], B2.m_v[0], B3.m_v[0]]); 201 SIMDScalar!(T, N) T1 = SIMDScalar!(T, N)([B0.m_v[1], B1.m_v[1], B2.m_v[1], B3.m_v[1]]); 202 SIMDScalar!(T, N) T2 = SIMDScalar!(T, N)([B0.m_v[2], B1.m_v[2], B2.m_v[2], B3.m_v[2]]); 203 SIMDScalar!(T, N) T3 = SIMDScalar!(T, N)([B0.m_v[3], B1.m_v[3], B2.m_v[3], B3.m_v[3]]); 204 205 B0 = T0; 206 B1 = T1; 207 B2 = T2; 208 B3 = T3; 209 } 210 211 private: 212 this(T)(T[] B) 213 { 214 foreach(i, v; B) 215 m_v[i] = v; 216 } 217 218 T[N] m_v; 219 }