aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/libs/base64/avx2/dec_avx2.c
blob: 90dde140fb61858e96d8f08c4e26f20d3c44a8f9 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
// If we have AVX2 support, pick off 32 bytes at a time for as long as we can, 
// but make sure that we quit before seeing any == markers at the end of the 
// string. Also, because we write 8 zeroes at the end of the output, ensure 
// that there are at least 11 valid bytes of input data remaining to close the 
// gap. 32 + 2 + 11 = 45 bytes: 
while (srclen >= 45) 
{ 
	// Load string: 
	__m256i str = _mm256_loadu_si256((__m256i *)c); 
 
	// The input consists of six character sets in the Base64 alphabet, 
	// which we need to map back to the 6-bit values they represent. 
	// There are three ranges, two singles, and then there's the rest. 
	// 
	//  #  From       To        Add  Characters 
	//  1  [43]       [62]      +19  + 
	//  2  [47]       [63]      +16  / 
	//  3  [48..57]   [52..61]   +4  0..9 
	//  4  [65..90]   [0..25]   -65  A..Z 
	//  5  [97..122]  [26..51]  -71  a..z 
	// (6) Everything else => invalid input 
 
	const __m256i set1 = CMPEQ(str, '+'); 
	const __m256i set2 = CMPEQ(str, '/'); 
	const __m256i set3 = RANGE(str, '0', '9'); 
	const __m256i set4 = RANGE(str, 'A', 'Z'); 
	const __m256i set5 = RANGE(str, 'a', 'z'); 
	const __m256i set6 = CMPEQ(str, '-'); 
	const __m256i set7 = CMPEQ(str, '_'); 
 
	__m256i delta = REPLACE(set1, 19); 
	delta = _mm256_or_si256(delta, REPLACE(set2,  16)); 
	delta = _mm256_or_si256(delta, REPLACE(set3,   4)); 
	delta = _mm256_or_si256(delta, REPLACE(set4, -65)); 
	delta = _mm256_or_si256(delta, REPLACE(set5, -71)); 
	delta = _mm256_or_si256(delta, REPLACE(set6, 17)); 
	delta = _mm256_or_si256(delta, REPLACE(set7, -32)); 
 
	// Check for invalid input: if any of the delta values are zero, 
	// fall back on bytewise code to do error checking and reporting: 
#ifdef _MSC_VER
	// Hack for MSVC miscompilation - it inserts vzeroupper for the break
	// (we need to clear YMM registers before exiting the function)
	// while delta and str are still in the registers.
	// Save delta/str in memory manually.
	_mm256_zeroupper();
#endif    
	if (_mm256_movemask_epi8(CMPEQ(delta, 0))) { 
		break; 
	} 
 
	// Now simply add the delta values to the input: 
	str = _mm256_add_epi8(str, delta); 
 
	// Reshuffle the input to packed 12-byte output format: 
	str = dec_reshuffle(str); 
 
	// Store back: 
	_mm256_storeu_si256((__m256i *)o, str); 
 
	c += 32; 
	o += 24; 
	outl += 24; 
	srclen -= 32; 
}