ReactOS 0.4.17-dev-1005-g171e1de
xtsaes_definitions.h
Go to the documentation of this file.
1//
2// xtsaes_definitions.h
3//
4// Copyright (c) Microsoft Corporation. Licensed under the MIT license.
5//
6
7//
8// Multiply by alpha
9//
10// <</>> indicate shifts on 128-bit values
11// <<<</>>>> indicate shifts on 32-bit values (a word)
12//
13
14// Multiply by ALPHA
15// Since there's no instruction to shift the 128 bit register left by one, the following shifts do the trick.
16// All shifts are zero extended
17// t1 = _in <<<< 1 words shifted left by 1, this is almost a _in << 1 but there are
18// gaps at first bit of each word, the following two shifts fixes that.
19// t2 = _in >>>> 31 words shifted right by 31
20// t1 = t1 ^ (t2 << 32) t1 = _in << 1, note ^ could be |
21// Do the special case for first byte of _in where last carry means xor with 135 for first byte.
22// t2 = t2 >> 96 t2 = _in >> 127, i.e., last bit of _in is placed in first bit
23// t2 = (t2 <<<< 7) + (t2 <<<<3) - (t2) t2 = 135 if last bit of t2 is set
24// res = t1 ^ t2
25#define XTS_MUL_ALPHA_old( _in, _res ) \
26{\
27 __m128i _t1, _t2;\
28\
29 _t1 = _mm_slli_epi32( _in, 1 ); \
30 _t2 = _mm_srli_epi32( _in, 31); \
31 _t1 = _mm_xor_si128( _t1, _mm_slli_si128( _t2, 4 )); \
32 _t2 = _mm_srli_si128( _t2, 12 ); \
33 _t2 = _mm_sub_epi32( _mm_add_epi32( _mm_slli_epi32( _t2, 7 ), _mm_slli_epi32( _t2, 3 ) ), _t2 ); \
34 _res = _mm_xor_si128( _t1, _t2 ); \
35}
36
37// An improved approach; use arithmetic shift-right to duplicate the carry-out, PSHUFD to re-arrange, and an AND to
38// implement both the polynomial and mask the other words down to 1 bit again.
39
40// __m128i XTS_ALPHA_MASK = _mm_set_epi32( 1, 1, 1, 0x87 );
41#define XTS_MUL_ALPHA( _in, _res ) \
42{\
43 __m128i _t1, _t2;\
44\
45 _t1 = _mm_slli_epi32( _in, 1 ); \
46 _t2 = _mm_srai_epi32( _in, 31); \
47 _t2 = _mm_shuffle_epi32( _t2, _MM_SHUFFLE( 2, 1, 0, 3 ) ); \
48 _t2 = _mm_and_si128( _t2, XTS_ALPHA_MASK ); \
49 _res = _mm_xor_si128( _t1, _t2 ); \
50}
51
52// Like XTS_MUL_ALPHA_old but operate on __m512i for _in and _res.
53// TODO: do this with VSHUFPS.
54#define XTS_MUL_ALPHA_ZMM_old( _in, _res ) \
55{\
56 __m512i _t1, _t2;\
57\
58 _t1 = _mm512_slli_epi32( _in, 1 ); \
59 _t2 = _mm512_srli_epi32( _in, 31); \
60 _t1 = _mm512_xor_si512( _t1, _mm512_bslli_epi128( _t2, 4 )); \
61 _t2 = _mm512_bsrli_epi128( _t2, 12 ); \
62 _t2 = _mm512_sub_epi32( _mm512_add_epi32( _mm512_slli_epi32( _t2, 7 ), _mm512_slli_epi32( _t2, 3 ) ), _t2 ); \
63 _res = _mm512_xor_si512( _t1, _t2 ); \
64}
65
66// Multiply by ALPHA^2
67// t1 = Input <<<< 2
68// t2 = Input >>>> 30
69// t1 = t1 ^ (t2 << 32)
70// t2 = t2 >> 96
71// t2 = (t2 <<<< 7) ^ (t2 <<<< 2) ^ (t2 <<<< 1) ^ t2
72// res = t1 ^ t2
73#define XTS_MUL_ALPHA2( _in, _res ) \
74{\
75 __m128i _t1, _t2;\
76\
77 _t1 = _mm_slli_epi32( _in, 2 ); \
78 _t2 = _mm_srli_epi32( _in, 30); \
79 _t1 = _mm_xor_si128( _t1, _mm_slli_si128( _t2, 4 )); \
80 _t2 = _mm_srli_si128( _t2, 12 ); \
81 _t2 = _mm_xor_si128( _mm_xor_si128( _mm_xor_si128( _mm_slli_epi32( _t2, 7 ), _mm_slli_epi32( _t2, 2 ) ), _mm_slli_epi32( _t2, 1 )), _t2 ); \
82 _res = _mm_xor_si128( _t1, _t2 ); \
83}
84
85// Multiply by ALPHA^4
86// t1 = Input <<<< 4
87// t2 = Input >>>> 28
88// t1 = t1 ^ (t2 << 32)
89// t2 = t2 >> 96
90// t2 = (t2 <<<< 7) ^ (t2 <<<< 2) ^ (t2 <<<< 1) ^ t2
91// res = t1 ^ t2
92#define XTS_MUL_ALPHA4( _in, _res ) \
93{\
94 __m128i _t1, _t2;\
95\
96 _t1 = _mm_slli_epi32( _in, 4 ); \
97 _t2 = _mm_srli_epi32( _in, 28); \
98 _t1 = _mm_xor_si128( _t1, _mm_slli_si128( _t2, 4 )); \
99 _t2 = _mm_srli_si128( _t2, 12 ); \
100 _t2 = _mm_xor_si128( _mm_xor_si128( _mm_xor_si128( _mm_slli_epi32( _t2, 7 ), _mm_slli_epi32( _t2, 2 ) ), _mm_slli_epi32( _t2, 1 )), _t2 ); \
101 _res = _mm_xor_si128( _t1, _t2 ); \
102}
103
104#define XTS_MUL_ALPHA5( _in, _res ) \
105{\
106 __m128i _t1, _t2;\
107\
108 _t1 = _mm_slli_epi32( _in, 5 ); \
109 _t2 = _mm_srli_epi32( _in, 27); \
110 _t1 = _mm_xor_si128( _t1, _mm_slli_si128( _t2, 4 )); \
111 _t2 = _mm_srli_si128( _t2, 12 ); \
112 _t2 = _mm_xor_si128( _mm_xor_si128( _mm_xor_si128( _mm_slli_epi32( _t2, 7 ), _mm_slli_epi32( _t2, 2 ) ), _mm_slli_epi32( _t2, 1 )), _t2 ); \
113 _res = _mm_xor_si128( _t1, _t2 ); \
114}
115
116
117// Multiply by ALPHA^8
118// t2 = Input >> 120
119// t2 = (t2 <<<< 7) ^ (t2 <<<< 2) ^ (t2 <<<< 1) ^ t2
120// res = (Input << 8) ^ t2
121//
122// Only currently used with VPCLMULQDQ (in Ymm / Zmm versions) as support for non-vectorized PCLMULQDQ is not always supported with AESNI,
123// and is sometimes slower than shift+xor
124
125// __m256i XTS_ALPHA_MULTIPLIER_Ymm = _mm256_set_epi64x( 0, 0x87, 0, 0x87);
126#define XTS_MUL_ALPHA8_YMM( _in, _res ) \
127{\
128 __m256i _t2;\
129\
130 _t2 = _mm256_srli_si256( _in, 15 ); /* AVX2 */ \
131 _res = _mm256_slli_si256( _in, 1 ); \
132 _t2 = _mm256_clmulepi64_epi128( _t2, XTS_ALPHA_MULTIPLIER_Ymm, 0x00 ); \
133 _res = _mm256_xor_si256( _res, _t2 ); \
134}
135
136#define XTS_MUL_ALPHA16_YMM( _in, _res ) \
137{\
138 __m256i _t2;\
139\
140 _t2 = _mm256_srli_si256( _in, 14 ); /* AVX2 */ \
141 _res = _mm256_slli_si256( _in, 2 ); \
142 _t2 = _mm256_clmulepi64_epi128( _t2, XTS_ALPHA_MULTIPLIER_Ymm, 0x00 ); \
143 _res = _mm256_xor_si256( _res, _t2 ); \
144}
145
146// __m512i XTS_ALPHA_MULTIPLIER_Zmm = _mm512_set_epi64( 0, 0x87, 0, 0x87, 0, 0x87, 0, 0x87 );
147#define XTS_MUL_ALPHA8_ZMM( _in, _res ) \
148{\
149 __m512i _t2; \
150\
151 _t2 = _mm512_bsrli_epi128( _in, 15 ); \
152 _res = _mm512_bslli_epi128( _in, 1 ); \
153 _t2 = _mm512_clmulepi64_epi128( _t2, XTS_ALPHA_MULTIPLIER_Zmm, 0x00 ); \
154 _res = _mm512_xor_si512( _res, _t2 ); \
155}
156
157#define XTS_MUL_ALPHA16_ZMM( _in, _res ) \
158{\
159 __m512i _t2; \
160\
161 _t2 = _mm512_bsrli_epi128( _in, 14 ); \
162 _res = _mm512_bslli_epi128( _in, 2 ); \
163 _t2 = _mm512_clmulepi64_epi128( _t2, XTS_ALPHA_MULTIPLIER_Zmm, 0x00 ); \
164 _res = _mm512_xor_si512( _res, _t2 ); \
165}
166
167// Currently only use UINT64 for x86 and amd64 - this does regress perf on x86
168// but we don't expect a lot of XTS in x86. If the regression causes any real problems
169// we can consider introducing another variant. Not doing this now to avoid code bloat
170#define XTS_MUL_ALPHA_Scalar( _inout_low_u64, _inout_high_u64 ) \
171{ \
172 UINT64 tmp = (UINT64) ((INT64)_inout_high_u64 >> 63); \
173 \
174 _inout_high_u64 = (_inout_high_u64 << 1) ^ (_inout_low_u64 >> 63); \
175 _inout_low_u64 = (_inout_low_u64 << 1) ^ (tmp & 0x87); \
176}