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 }