1 /** 2 * Lightweight wrappers around AltiVec for 32-bit operations 3 * 4 * Copyright: 5 * (C) 2009 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_altivec; 12 13 import botan.constants; 14 static if (BOTAN_HAS_SIMD_ALTIVEC): 15 16 import botan.utils.loadstor; 17 import botan.utils.cpuid; 18 import botan.utils.simd.altivec; 19 20 struct SIMDAltivec 21 { 22 public: 23 static bool enabled() { return CPUID.hasAltivec(); } 24 25 this(in uint[4] B) 26 { 27 m_reg = [B[0], B[1], B[2], B[3]]; 28 } 29 30 this(uint B0, uint B1, uint B2, uint B3) 31 { 32 m_reg = [B0, B1, B2, B3]; 33 } 34 35 this(uint B) 36 { 37 m_reg = [B, B, B, B]; 38 } 39 40 static SIMDAltivec loadLittleEndian(in void* input) 41 { 42 const uint* in_32 = cast(const uint*)(input); 43 44 vector_uint R0 = vec_ld(0, in_32); 45 vector_uint R1 = vec_ld(12, in_32); 46 47 vector_byte perm = vec_lvsl(0, in_32); 48 49 perm = vec_xor(perm, vec_splat_u8(3)); 50 51 R0 = vec_perm(R0, R1, perm); 52 53 return SIMDAltivec(R0); 54 } 55 56 static SIMDAltivec loadBigEndian(in void* input) 57 { 58 const uint* in_32 = cast(const uint*)(input); 59 60 vector_uint R0 = vec_ld(0, in_32); 61 vector_uint R1 = vec_ld(12, in_32); 62 63 vector_byte perm = vec_lvsl(0, in_32); 64 65 R0 = vec_perm(R0, R1, perm); 66 67 return SIMDAltivec(R0); 68 } 69 70 void storeLittleEndian(ubyte* output) 71 { 72 vector_byte perm = vec_lvsl(0, null); 73 74 perm = vec_xor(perm, vec_splat_u8(3)); 75 76 union { 77 vector_uint V; 78 uint[4] R; 79 } vec; 80 81 vec.V = vec_perm(m_reg, m_reg, perm); 82 83 .storeBigEndian(output, vec.R[0], vec.R[1], vec.R[2], vec.R[3]); 84 } 85 86 void storeBigEndian(ubyte* output) 87 { 88 union { 89 vector_uint V; 90 uint[4] R; 91 } vec; 92 93 vec.V = m_reg; 94 95 .storeBigEndian(output, vec.R[0], vec.R[1], vec.R[2], vec.R[3]); 96 } 97 98 void rotateLeft(int rot)() 99 { 100 vector_uint rot_vec = vector_uint([rot, rot, rot, rot]); 101 102 m_reg = vec_rl(m_reg, rot_vec); 103 } 104 105 void rotateRight(int rot)() 106 { 107 this.rotateLeft!(32 - rot)(); 108 } 109 110 void opOpAssign(string op)(in SIMDAltivec other) 111 if (op == "+") 112 { 113 m_reg = vec_add(m_reg, other.m_reg); 114 } 115 116 SIMDAltivec opBinary(string op)(in SIMDAltivec other) 117 if (op == "+") 118 { 119 return SIMDAltivec(vec_add(m_reg, other.m_reg)); 120 } 121 122 void opOpAssign(string op)(in SIMDAltivec other) 123 if (op == "-") 124 { 125 m_reg = vec_sub(m_reg, other.m_reg); 126 } 127 128 SIMDAltivec opBinary(string op)(in SIMDAltivec other) 129 if (op == "-") 130 { 131 return SIMDAltivec(vec_sub(m_reg, other.m_reg)); 132 } 133 134 void opOpAssign(string op)(in SIMDAltivec other) 135 if (op == "^") 136 { 137 m_reg = vec_xor(m_reg, other.m_reg); 138 } 139 140 SIMDAltivec opBinary(string op)(in SIMDAltivec other) 141 if (op == "^") 142 { 143 return SIMDAltivec(vec_xor(m_reg, other.m_reg)); 144 } 145 146 void opOpAssign(string op)(in SIMDAltivec other) 147 if (op == "|") 148 { 149 m_reg = vec_or(m_reg, other.m_reg); 150 } 151 152 SIMDAltivec opBinary(string op)(in SIMDAltivec other) 153 if (op == "&") 154 { 155 return SIMDAltivec(vec_and(m_reg, other.m_reg)); 156 } 157 158 void opOpAssign(string op)(in SIMDAltivec other) 159 if (op == "&") 160 { 161 m_reg = vec_and(m_reg, other.m_reg); 162 } 163 164 SIMDAltivec lshift(int shift_)() 165 { 166 uint shift = cast(uint) shift_; 167 vector_uint shift_vec = vector_uint([shift, shift, shift, shift]); 168 169 return SIMDAltivec(vec_sl(m_reg, shift_vec)); 170 } 171 172 SIMDAltivec rshift(int shift_)() 173 { 174 uint shift = cast(uint) shift_; 175 vector_uint shift_vec = vector_uint([shift, shift, shift, shift]); 176 177 return SIMDAltivec(vec_sr(m_reg, shift_vec)); 178 } 179 180 SIMDAltivec opUnary(string op)() 181 if (op == "~") 182 { 183 return SIMDAltivec(vec_nor(m_reg, m_reg)); 184 } 185 186 SIMDAltivec andc(in SIMDAltivec other) 187 { 188 // AltiVec does arg1 & ~arg2 rather than SSE's ~arg1 & arg2 189 return SIMDAltivec(vec_andc(other.m_reg, m_reg)); 190 } 191 192 SIMDAltivec bswap() 193 { 194 vector_byte perm = vec_lvsl(0, null); 195 196 perm = vec_xor(perm, vec_splat_u8(3)); 197 198 return SIMDAltivec(vec_perm(m_reg, m_reg, perm)); 199 } 200 201 static void transpose(ref SIMDAltivec B0, ref SIMDAltivec B1, 202 ref SIMDAltivec B2, ref SIMDAltivec B3) 203 { 204 vector_uint T0 = vec_mergeh(B0.m_reg, B2.m_reg); 205 vector_uint T1 = vec_mergel(B0.m_reg, B2.m_reg); 206 vector_uint T2 = vec_mergeh(B1.m_reg, B3.m_reg); 207 vector_uint T3 = vec_mergel(B1.m_reg, B3.m_reg); 208 209 B0.m_reg = vec_mergeh(T0, T2); 210 B1.m_reg = vec_mergel(T0, T2); 211 B2.m_reg = vec_mergeh(T1, T3); 212 B3.m_reg = vec_mergel(T1, T3); 213 } 214 215 private: 216 this(vector_uint input) { m_reg = input; } 217 218 vector_uint m_reg; 219 }