1 /** 2 * immintrin.h style functions 3 * 4 * Copyright: 5 * (C) 2014-2015 Etienne Cimon 6 * 7 * License: 8 * Released under the MIT license 9 */ 10 module botan.utils.simd.immintrin; 11 12 13 import botan.constants; 14 15 static if (BOTAN_HAS_THREEFISH_512_AVX2): 16 17 import core.simd; 18 19 alias __m256i = byte32; 20 21 pure: 22 nothrow: 23 @trusted: 24 25 int _MM_SHUFFLE(int a, int b, int c, int d) 26 { 27 return (z<<6) | (y<<4) | (x<<2) | w; 28 } 29 30 version(GDC) { 31 // GDC <--> immintrin => gcc/gcc/config/i386/immintrin.h 32 static import gcc.attribute; 33 import gcc.builtins; 34 enum inline = gcc.attribute.attribute("forceinline"); 35 enum avx2 = gcc.attribute.attribute("target", "avx2"); 36 37 @inline @avx2 38 __m256i _mm256_unpacklo_epi64(__m256i a, __m256i b) { 39 return cast(__m256i) __builtin_ia32_punpcklqdq256(cast(long4) a, cast(long4) b); 40 } 41 42 43 @inline @avx2 44 __m256i _mm256_unpackhi_epi64(__m256i a, __m256i b) { 45 return cast(__m256i) __builtin_ia32_punpckhqdq256(cast(long4) a, cast(long4) b); 46 } 47 48 @inline @avx2 49 __m256i _mm256_set_epi64x(long a, long b, long c, long d) { 50 return cast(__m256i) long4([a, b, c, d]); 51 } 52 53 @inline @avx2 54 void _mm256_storeu_si256(__m256i* ptr, __m256i a) { 55 __builtin_ia32_storedqu256(ptr, a); 56 return; 57 } 58 59 @inline @avx2 60 __m256i _mm256_loadu_si256(__m256i* ptr) { 61 return cast(__m256i) __builtin_ia32_loaddqu256(ptr); 62 } 63 64 65 @inline @avx2 66 __m256i _mm256_permute4x64_epi64(__m256 X, in int M) { 67 return cast(__m256i) __builtin_ia32_permdi256(cast(long4) X, M); 68 } 69 70 @inline @avx2 71 __m256i _mm256_add_epi64(__m256 a, __m256 b) { 72 return cast(__m256i) __builtin_ia32_paddq256(cast(long4) a, cast(long4) b); 73 } 74 75 @inline @avx2 76 __m256i _mm256_sub_epi64(__m256 a, __m256 b) { 77 return cast(__m256i) __builtin_ia32_psubq256(cast(long4) a, cast(long4) b); 78 } 79 80 @inline @avx2 81 __m256i _mm256_xor_si256(__m256 a, __m256 b) { 82 return cast(__m256i) __builtin_ia32_pxor256(cast(long4) a, cast(long4) b); 83 } 84 85 @inline @avx2 86 __m256i _mm256_or_si256(__m256 a, __m256 b) { 87 return cast(__m256i) __builtin_ia32_por256(cast(long4) a, cast(long4) b); 88 } 89 90 @inline @avx2 91 __m256i _mm256_srlv_epi64(__m256 a, __m256 b) { 92 return cast(__m256i) __builtin_ia32_psrlv4di(cast(long4) a, cast(long4) b); 93 } 94 95 @inline @avx2 96 __m256i _mm256_sllv_epi64(__m256 a, __m256 b) { 97 return cast(__m256i) __builtin_ia32_psllv4di(cast(long4) a, cast(long4) b); 98 } 99 100 101 } 102 103 version(none) { 104 // LDC <--> immintrin ==> clang/test/CodeGen/avx2-builtins.c, rdrand-builtins.c 105 106 pragma(LDC_inline_ir) 107 R inlineIR(string s, R, P...)(P); 108 109 pragma(LDC_intrinsic, "llvm.x86.rdrand.32") 110 int _rdrand32_step(uint*); 111 112 __m256i _mm256_set_epi64x(long a, long b, long c, long d) { 113 return cast(__m256i) long4([a, b, c, d]); 114 } 115 116 __m256i _mm256_unpacklo_epi64(__m256i a, __m256i b) { 117 pragma(LDC_allow_inline); 118 return inlineIR!(` 119 %tmp = shufflevector <4 x i64> %0, <4 x i64> %1, <4 x i32> <i32 0, i32 4, i32 2, i32 6> 120 ret <4 x i64> %tmp`, 121 __m256i)(a, b); 122 } 123 124 __m256i _mm256_unpackhi_epi64(__m256i a, __m256i b) { 125 pragma(LDC_allow_inline); 126 return inlineIR!(` 127 %tmp = shufflevector <4 x i64> %0, <4 x i64> %1, <4 x i32> <i32 1, i32 5, i32 3, i32 7> 128 ret <4 x i64> %tmp`, 129 __m256i)(a, b); 130 } 131 132 __m256i _mm256_loadu_si256(__m256i* a) { 133 pragma(LDC_allow_inline); 134 return inlineIR!(` 135 %tmp = load <4 x i64>* %0, align 1 136 ret <4 x i64> %tmp`, 137 __m256i)(a); 138 139 } 140 141 void _mm256_storeu_si256(__m256i* ptr, __m256i a) { 142 pragma(LDC_allow_inline); 143 return inlineIR!(`store <4 x i64> %1, <4 x i64>* %0 144 ret`, 145 void)(ptr, a); 146 147 } 148 149 __m256i _mm256_permute4x64_epi64(__m256i a, in int M) { 150 pragma(LDC_allow_inline); 151 152 int[4] val = [(M) & 0x3, ((M) & 0xc) >> 2, ((M) & 0x30) >> 4, ((M) & 0xc0) >> 6]; 153 return inlineIR!(`%tmp = shufflevector <4 x i64> %0, <4 x i64> undef, <i32 %1, i32 %2, i32 %3, i32 %4> 154 ret <4 x i64> %tmp`, 155 __m256i)(a, val[0], val[1], val[2], val[3]); 156 } 157 158 __m256i _mm256_add_epi64(__m256i a, __m256i b) { 159 pragma(LDC_allow_inline); 160 return inlineIR!(`%tmp = add <4 x i64> %0, %1 161 ret <4 x i64> %tmp`, 162 __m256i)(a, b); 163 } 164 165 __m256i _mm256_sub_epi64(__m256i a, __m256i b) { 166 pragma(LDC_allow_inline); 167 return inlineIR!(`%tmp = sub <4 x i64> %0, %1 168 ret <4 x i64> %tmp`, 169 __m256i)(a, b); 170 } 171 172 __m256i _mm256_xor_si256(__m256i a, __m256i b) { 173 pragma(LDC_allow_inline); 174 return inlineIR!(`%tmp = xor <4 x i64> %0, %1 175 ret <4 x i64> %tmp`, 176 __m256i)(a, b); 177 } 178 179 __m256i _mm256_or_si256(__m256i a, __m256i b) { 180 pragma(LDC_allow_inline); 181 return inlineIR!(`%tmp = or <4 x i64> %0, %1 182 ret <4 x i64> %tmp`, 183 __m256i)(a, b); 184 } 185 186 pragma(LDC_intrinsic, "llvm.x86.avx2.psrlv.q.256") 187 __m256i _mm256_srlv_epi64(__m256i a, __m256i b); 188 189 pragma(LDC_intrinsic, "llvm.x86.avx2.psllv.q.256") 190 __m256i _mm256_sllv_epi64(__m256i a, __m256i b); 191 192 193 194 } 195 196 version(D_InlineAsm_X86_64) { 197 static assert(false, "DMD does not currently support AVX2."); 198 199 __m256i _mm256_unpacklo_epi64(__m256i a, __m256i b) 200 { 201 // http://www.felixcloutier.com/x86/PUNPCKLBW:PUNPCKLWD:PUNPCKLDQ:PUNPCKLQDQ.html 202 203 __m256i ret; 204 205 __m256i* _a = &a; 206 __m256i* _b = &b; 207 __m256i* _c = &ret; 208 209 asm 210 { 211 mov RAX, _a; 212 mov RBX, _b; 213 mov RCX, _c; 214 vpunpcklqdq [RCX], [RAX], [RBX]; 215 } 216 217 return ret; 218 219 } 220 221 __m256i _mm256_unpackhi_epi64(__m256i a, __m256i b) 222 { 223 // http://www.felixcloutier.com/x86/PUNPCKHBW:PUNPCKHWD:PUNPCKHDQ:PUNPCKHQDQ.html 224 225 __m256i ret; 226 227 __m256i* _a = &a; 228 __m256i* _b = &b; 229 __m256i* _c = &ret; 230 231 asm 232 { 233 mov RAX, _a; 234 mov RBX, _b; 235 mov RCX, _c; 236 vpunpckhqdq [RCX], [RAX], [RBX]; 237 } 238 239 return ret; 240 241 } 242 243 __m256i _mm256_set_epi64x(long a, long b, long c, long d) { 244 return cast(__m256i) long4([a, b, c, d]); 245 } 246 247 __m256i _mm256_loadu_si256(__m256i* a) 248 { 249 // http://www.felixcloutier.com/x86/MOVDQU.html 250 251 __m256i ret; 252 __m256i* b = &ret; 253 asm 254 { 255 mov RAX, a; 256 mov RBX, b; 257 vmovdqu YMM0, [RAX]; 258 vmovdqu [RBX], YMM0; 259 } 260 261 return ret; 262 263 } 264 265 void _mm256_storeu_si256(__m256i* ptr, __m256i a) { 266 267 __m256i ret; 268 __m256i* _a = &a; 269 __m256i* _b = &ret; 270 asm 271 { 272 mov RAX, _a; 273 mov RBX, _b; 274 vmovdqu YMM0, [RAX]; 275 vmovdqu [RBX], YMM0; 276 } 277 278 *ptr = ret; 279 280 } 281 282 __m256i _mm256_permute4x64_epi64(__m256i a, in int M) { 283 __m256i ret; 284 __m256i* _a = &a; 285 __m256i* _b = &ret; 286 ubyte[4] val = [cast(ubyte) ((M) & 0x3), cast(ubyte) (((M) & 0xc) >> 2), cast(ubyte) (((M) & 0x30) >> 4), cast(ubyte) (((M) & 0xc0) >> 6)]; 287 288 ubyte _imm8; 289 _imm8 |= (val >> 0) & 0x3; 290 _imm8 |= (val >> 2) & 0x3; 291 _imm8 |= (val >> 4) & 0x3; 292 _imm8 |= (val >> 6) & 0x3; 293 294 asm 295 { 296 mov imm8, _imm8; 297 mov RAX, _a; 298 mov RBX, _b; 299 vmovdqu YMM0, [RAX]; 300 vmovdqu [RBX], YMM0; 301 } 302 303 *ptr = ret; 304 } 305 306 // todo: Prepare the rest of the assembly. Use GDC/LDC in the meantime 307 308 } 309 310 // _mm256_unpacklo_epi64 311 // _mm256_unpackhi_epi64 312 // _mm256_set_epi64x 313 // _mm256_loadu_si256 314 // _mm256_storeu_si256 315 // _mm256_permute4x64_epi64 316 // _mm256_add_epi64 317 // _mm256_sub_epi64 318 // _mm256_xor_si256 319 // _mm256_or_si256 320 // _mm256_srlv_epi64 321 // _mm256_sllv_epi64 322 // _rdrand32_step => asm(".ubyte 0x0F, 0xC7, 0xF0; adcl $0,%1" : "=a" (r), "=r" (cf) : "0" (r), "1" (cf) : "cc");