Coverage Report

Created: 2026-10-16 07:31

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/openssl/crypto/evp/enc_b64_avx2.c
Line
Count
Source
1
#include <openssl/evp.h>
2
#include "enc_b64_scalar.h"
3
#include "enc_b64_avx2.h"
4
#include "b64_avx2_common.h"
5
6
#ifdef HAVE_AVX2
7
8
/*
9
 * Ensure this whole block is compiled with AVX2 enabled on GCC.
10
 * Clang/MSVC will just ignore these pragmas.
11
 */
12
OPENSSL_TARGET_AVX2
13
static __m256i lookup_pshufb_std(__m256i input)
14
0
{
15
0
    __m256i result = _mm256_subs_epu8(input, _mm256_set1_epi8(51));
16
0
    const __m256i less = _mm256_cmpgt_epi8(_mm256_set1_epi8(26), input);
17
18
0
    result = _mm256_or_si256(result, _mm256_and_si256(less, _mm256_set1_epi8(13)));
19
0
    __m256i shift_LUT = _mm256_setr_epi8('a' - 26, '0' - 52, '0' - 52, '0' - 52, '0' - 52,
20
0
        '0' - 52, '0' - 52,
21
0
        '0' - 52, '0' - 52, '0' - 52, '0' - 52, '+' - 62,
22
0
        '/' - 63, 'A', 0, 0,
23
0
        'a' - 26, '0' - 52, '0' - 52, '0' - 52, '0' - 52,
24
0
        '0' - 52, '0' - 52,
25
0
        '0' - 52, '0' - 52, '0' - 52, '0' - 52, '+' - 62,
26
0
        '/' - 63, 'A', 0, 0);
27
28
0
    result = _mm256_shuffle_epi8(shift_LUT, result);
29
0
    return _mm256_add_epi8(result, input);
30
0
}
31
OPENSSL_UNTARGET_AVX2
32
33
OPENSSL_TARGET_AVX2
34
static ossl_inline __m256i lookup_pshufb_srp(__m256i input)
35
0
{
36
0
    const __m256i zero = _mm256_setzero_si256();
37
0
    const __m256i hi = _mm256_set1_epi8((char)0x80);
38
0
    __m256i invalid = _mm256_or_si256(_mm256_cmpgt_epi8(zero, input),
39
0
        _mm256_cmpgt_epi8(input,
40
0
            _mm256_set1_epi8(63)));
41
0
    __m256i idx = _mm256_setzero_si256();
42
43
0
    idx = _mm256_sub_epi8(idx, _mm256_cmpgt_epi8(input, _mm256_set1_epi8(9)));
44
0
    idx = _mm256_sub_epi8(idx, _mm256_cmpgt_epi8(input, _mm256_set1_epi8(35)));
45
0
    idx = _mm256_blendv_epi8(idx, _mm256_set1_epi8(3),
46
0
        _mm256_cmpeq_epi8(input, _mm256_set1_epi8(62)));
47
0
    idx = _mm256_blendv_epi8(idx, _mm256_set1_epi8(4),
48
0
        _mm256_cmpeq_epi8(input, _mm256_set1_epi8(63)));
49
50
    /* Zero-out invalid lanes via PSHUFB's high-bit mechanism */
51
0
    idx = _mm256_or_si256(idx, _mm256_and_si256(invalid, hi));
52
53
0
    const __m256i shift_LUT = _mm256_setr_epi8('0' - 0, 'A' - 10, 'a' - 36, '.' - 62, '/' - 63, 0, 0,
54
0
        0, 0, 0, 0, 0, 0, 0, 0, 0,
55
0
        '0' - 0, 'A' - 10, 'a' - 36, '.' - 62, '/' - 63, 0, 0,
56
0
        0, 0, 0, 0, 0, 0, 0, 0, 0);
57
58
0
    __m256i shift = _mm256_shuffle_epi8(shift_LUT, idx);
59
0
    __m256i ascii = _mm256_add_epi8(shift, input);
60
0
    return ascii;
61
0
}
62
OPENSSL_UNTARGET_AVX2
63
64
OPENSSL_TARGET_AVX2
65
static ossl_inline __m256i shift_right_zeros(__m256i v, int n)
66
0
{
67
0
    switch (n) {
68
0
    case 0:
69
0
        return v;
70
0
    case 1:
71
0
        return _mm256_srli_si256(v, 1);
72
0
    case 2:
73
0
        return _mm256_srli_si256(v, 2);
74
0
    case 3:
75
0
        return _mm256_srli_si256(v, 3);
76
0
    case 4:
77
0
        return _mm256_srli_si256(v, 4);
78
0
    case 5:
79
0
        return _mm256_srli_si256(v, 5);
80
0
    case 6:
81
0
        return _mm256_srli_si256(v, 6);
82
0
    case 7:
83
0
        return _mm256_srli_si256(v, 7);
84
0
    case 8:
85
0
        return _mm256_srli_si256(v, 8);
86
0
    case 9:
87
0
        return _mm256_srli_si256(v, 9);
88
0
    case 10:
89
0
        return _mm256_srli_si256(v, 10);
90
0
    case 11:
91
0
        return _mm256_srli_si256(v, 11);
92
0
    case 12:
93
0
        return _mm256_srli_si256(v, 12);
94
0
    case 13:
95
0
        return _mm256_srli_si256(v, 13);
96
0
    case 14:
97
0
        return _mm256_srli_si256(v, 14);
98
0
    case 15:
99
0
        return _mm256_srli_si256(v, 15);
100
0
    default:
101
0
        return _mm256_setzero_si256();
102
0
    }
103
0
}
104
OPENSSL_UNTARGET_AVX2
105
106
OPENSSL_TARGET_AVX2
107
static ossl_inline __m256i shift_left_zeros(__m256i v, int n)
108
0
{
109
0
    switch (n) {
110
0
    case 0:
111
0
        return v;
112
0
    case 1:
113
0
        return _mm256_slli_si256(v, 1);
114
0
    case 2:
115
0
        return _mm256_slli_si256(v, 2);
116
0
    case 3:
117
0
        return _mm256_slli_si256(v, 3);
118
0
    case 4:
119
0
        return _mm256_slli_si256(v, 4);
120
0
    case 5:
121
0
        return _mm256_slli_si256(v, 5);
122
0
    case 6:
123
0
        return _mm256_slli_si256(v, 6);
124
0
    case 7:
125
0
        return _mm256_slli_si256(v, 7);
126
0
    case 8:
127
0
        return _mm256_slli_si256(v, 8);
128
0
    case 9:
129
0
        return _mm256_slli_si256(v, 9);
130
0
    case 10:
131
0
        return _mm256_slli_si256(v, 10);
132
0
    case 11:
133
0
        return _mm256_slli_si256(v, 11);
134
0
    case 12:
135
0
        return _mm256_slli_si256(v, 12);
136
0
    case 13:
137
0
        return _mm256_slli_si256(v, 13);
138
0
    case 14:
139
0
        return _mm256_slli_si256(v, 14);
140
0
    case 15:
141
0
        return _mm256_slli_si256(v, 15);
142
0
    case 16:
143
0
        return _mm256_setzero_si256();
144
0
    default:
145
0
        return _mm256_setzero_si256();
146
0
    }
147
0
}
148
OPENSSL_UNTARGET_AVX2
149
150
static const uint8_t shuffle_masks[16][16] = {
151
    { 0x80, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 },
152
    { 0, 0x80, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 },
153
    { 0, 1, 0x80, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 },
154
    { 0, 1, 2, 0x80, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 },
155
    { 0, 1, 2, 3, 0x80, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 },
156
    { 0, 1, 2, 3, 4, 0x80, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 },
157
    { 0, 1, 2, 3, 4, 5, 0x80, 6, 7, 8, 9, 10, 11, 12, 13, 14 },
158
    { 0, 1, 2, 3, 4, 5, 6, 0x80, 7, 8, 9, 10, 11, 12, 13, 14 },
159
    { 0, 1, 2, 3, 4, 5, 6, 7, 0x80, 8, 9, 10, 11, 12, 13, 14 },
160
    { 0, 1, 2, 3, 4, 5, 6, 7, 8, 0x80, 9, 10, 11, 12, 13, 14 },
161
    { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0x80, 10, 11, 12, 13, 14 },
162
    { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0x80, 11, 12, 13, 14 },
163
    { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0x80, 12, 13, 14 },
164
    { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0x80, 13, 14 },
165
    { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 0x80, 14 },
166
    { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 0x80 }
167
};
168
169
/**
170
 * Insert a line feed character in the 64-byte input at index K in [0,32).
171
 */
172
OPENSSL_TARGET_AVX2
173
static ossl_inline __m256i insert_line_feed32(__m256i input, int K)
174
0
{
175
0
    __m256i line_feed_vector = _mm256_set1_epi8('\n');
176
0
    __m128i identity = _mm_setr_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
177
178
0
    if (K >= 16) {
179
0
        __m128i maskhi = _mm_loadu_si128((__m128i *)shuffle_masks[K - 16]);
180
0
        __m256i mask = _mm256_set_m128i(maskhi, identity);
181
0
        __m256i lf_pos = _mm256_cmpeq_epi8(mask, _mm256_set1_epi8((char)0x80));
182
0
        __m256i shuffled = _mm256_shuffle_epi8(input, mask);
183
0
        __m256i result = _mm256_blendv_epi8(shuffled, line_feed_vector, lf_pos);
184
185
0
        return result;
186
0
    }
187
    /* Shift input right by 1 byte */
188
0
    __m256i shift = _mm256_alignr_epi8(input, _mm256_permute2x128_si256(input, input, 0x21),
189
0
        15);
190
0
    input = _mm256_blend_epi32(input, shift, 0xF0);
191
0
    __m128i masklo = _mm_loadu_si128((__m128i *)shuffle_masks[K]);
192
0
    __m256i mask = _mm256_set_m128i(identity, masklo);
193
0
    __m256i lf_pos = _mm256_cmpeq_epi8(mask, _mm256_set1_epi8((char)0x80));
194
0
    __m256i shuffled = _mm256_shuffle_epi8(input, mask);
195
0
    __m256i result = _mm256_blendv_epi8(shuffled, line_feed_vector, lf_pos);
196
0
    return result;
197
0
}
198
OPENSSL_UNTARGET_AVX2
199
200
OPENSSL_TARGET_AVX2
201
static ossl_inline size_t ins_nl_gt32(__m256i v, uint8_t *out, int stride,
202
    int *wrap_cnt)
203
0
{
204
0
    const int until_nl = stride - *wrap_cnt;
205
206
0
    if (until_nl > 32) {
207
0
        _mm256_storeu_si256((__m256i *)out, v);
208
209
0
        *wrap_cnt += 32;
210
0
        return 32;
211
0
    }
212
213
0
    if (until_nl == 32) {
214
0
        _mm256_storeu_si256((__m256i *)out, v);
215
216
0
        out[32] = '\n';
217
0
        *wrap_cnt = 0;
218
0
        return 33;
219
0
    }
220
221
0
    const uint8_t last = (uint8_t)_mm256_extract_epi8(v, 31);
222
0
    const __m256i with_lf = insert_line_feed32(v, until_nl);
223
0
    _mm256_storeu_si256((__m256i *)out, with_lf);
224
0
    out[32] = last;
225
226
0
    *wrap_cnt = 32 - until_nl;
227
0
    return 33;
228
0
}
229
OPENSSL_UNTARGET_AVX2
230
231
OPENSSL_TARGET_AVX2
232
static ossl_inline size_t insert_nl_gt16(const __m256i v0,
233
    uint8_t *output,
234
    int wrap_max, int *wrap_cnt)
235
0
{
236
0
    uint8_t *out = output;
237
0
    int wrap_rem = wrap_max - *wrap_cnt;
238
0
    _mm256_storeu_si256((__m256i *)(output), v0);
239
240
0
    if (wrap_rem > 32) {
241
0
        *wrap_cnt += 32;
242
0
        return 32;
243
0
    }
244
245
0
    __m256i all_ff_mask = _mm256_set1_epi8((char)0xFF);
246
247
0
    __m256i mask_second_lane = _mm256_setr_epi8(0, 0, 0, 0, 0, 0, 0, 0,
248
0
        0, 0, 0, 0, 0, 0, 0, 0,
249
0
        (char)0xFF, (char)0xFF, (char)0xFF, (char)0xFF,
250
0
        (char)0xFF, (char)0xFF, (char)0xFF, (char)0xFF,
251
0
        (char)0xFF, (char)0xFF, (char)0xFF, (char)0xFF,
252
0
        (char)0xFF, (char)0xFF, (char)0xFF, (char)0xFF);
253
254
0
    __m256i blended_0L = v0;
255
0
    int surplus_0 = wrap_rem < 16 ? 1 : 0;
256
0
    if (surplus_0 == 1) {
257
0
        __m256i shifted_0_L = shift_left_zeros(shift_right_zeros(v0, wrap_rem),
258
0
            wrap_rem + surplus_0);
259
0
        __m256i mask_shifted_0_L = shift_left_zeros(all_ff_mask, wrap_rem + surplus_0);
260
0
        __m256i mask = _mm256_or_si256(mask_shifted_0_L, mask_second_lane);
261
0
        __m256i shifted_1_L = shift_left_zeros(v0, 1);
262
0
        __m256i shifted = _mm256_blendv_epi8(shifted_0_L, shifted_1_L, mask);
263
264
0
        blended_0L = _mm256_blendv_epi8(v0, shifted, mask);
265
0
        _mm256_storeu_si256((__m256i *)(output), blended_0L);
266
0
        wrap_rem += wrap_max;
267
0
    }
268
269
0
    int surplus_1 = (wrap_rem >= 16 && wrap_rem < 32) ? 1 : 0;
270
0
    int last_of_1L = _mm256_extract_epi8(v0, 31);
271
272
0
    if (surplus_1 == 1) {
273
0
        uint16_t sec_last_of_1L = _mm256_extract_epi8(v0, 30);
274
0
        int wrap_rem_1 = wrap_rem - 16;
275
0
        __m256i shifted_1_L = shift_left_zeros(shift_right_zeros(v0, wrap_rem_1),
276
0
            wrap_rem_1 + surplus_0 + surplus_1);
277
0
        __m256i mask_shifted_1_L = shift_left_zeros(all_ff_mask, wrap_rem_1 + surplus_0 + surplus_1);
278
0
        __m256i mask = _mm256_and_si256(mask_second_lane, mask_shifted_1_L);
279
0
        __m256i blended_1L = _mm256_blendv_epi8(blended_0L, shifted_1_L, mask);
280
0
        _mm256_storeu_si256((__m256i *)(output), blended_1L);
281
282
0
        output[wrap_rem + surplus_0] = '\n';
283
0
        output[31 + surplus_0] = (uint8_t)sec_last_of_1L;
284
0
        output[31 + surplus_0 + surplus_1] = last_of_1L;
285
0
    }
286
287
0
    if (surplus_0 == 1) {
288
0
        output[wrap_rem - wrap_max] = '\n';
289
0
        output[16] = _mm256_extract_epi8(v0, 15);
290
0
        output[31 + surplus_0 + surplus_1] = last_of_1L;
291
0
    }
292
293
0
    *wrap_cnt = wrap_rem > 32 ? 32 - (wrap_rem - wrap_max) : 32 - wrap_rem;
294
295
0
    int nl_at_end = 0;
296
0
    if (*wrap_cnt == wrap_max || *wrap_cnt == 0) {
297
0
        *wrap_cnt = 0;
298
0
        output[32 + surplus_0 + surplus_1] = '\n';
299
0
        nl_at_end = 1;
300
0
    }
301
302
0
    out += 32 + surplus_0 + surplus_1 + nl_at_end;
303
0
    size_t written = (size_t)(out - output);
304
305
0
    return written;
306
0
}
307
OPENSSL_UNTARGET_AVX2
308
309
OPENSSL_TARGET_AVX2
310
static ossl_inline size_t insert_nl_2nd_vec_stride_12(const __m256i v0,
311
    uint8_t *output,
312
    int dummy_stride,
313
    int *wrap_cnt)
314
0
{
315
0
    __m256i shuffling_mask = _mm256_setr_epi8(0, 1, 2, 3, (char)0xFF, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
316
0
        (char)0xFF,
317
0
        (char)0xFF, (char)0xFF, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, (char)0xFF,
318
0
        12);
319
0
    __m256i shuffled = _mm256_shuffle_epi8(v0, shuffling_mask);
320
321
0
    _mm256_storeu_si256((__m256i *)(output + 0), shuffled);
322
323
0
    int16_t rem_1_L_ext = _mm256_extract_epi16(v0, 7);
324
0
    int8_t rem_2_L_ext_P1 = _mm256_extract_epi8(v0, 29);
325
0
    int16_t rem_2_L_ext_P2 = _mm256_extract_epi16(v0, 15);
326
327
0
    uint8_t *out = output;
328
0
    out[4] = '\n';
329
0
    memcpy(out + 15, &rem_1_L_ext, sizeof(rem_1_L_ext));
330
0
    out[16 + 1] = '\n';
331
0
    memcpy(out + 15 + 17, &rem_2_L_ext_P1, sizeof(rem_2_L_ext_P1));
332
0
    out[16 + 14] = '\n';
333
0
    memcpy(out + 15 + 17 + 1, &rem_2_L_ext_P2, sizeof(rem_2_L_ext_P2));
334
335
0
    out += 32 + 3;
336
0
    *wrap_cnt = 4;
337
338
0
    size_t written = (out - output);
339
0
    return written;
340
0
}
341
OPENSSL_UNTARGET_AVX2
342
343
OPENSSL_TARGET_AVX2
344
static ossl_inline __m256i insert_newlines_by_mask(__m256i data, __m256i mask)
345
0
{
346
0
    __m256i newline = _mm256_set1_epi8('\n');
347
348
0
    return _mm256_or_si256(_mm256_and_si256(mask, newline),
349
0
        _mm256_andnot_si256(mask, data));
350
0
}
351
OPENSSL_UNTARGET_AVX2
352
353
OPENSSL_TARGET_AVX2
354
static ossl_inline size_t insert_nl_str4(const __m256i v0, uint8_t *output)
355
0
{
356
0
    __m256i shuffling_mask = _mm256_setr_epi8(0, 1, 2, 3, (char)0xFF, 4, 5, 6,
357
0
        7, (char)0xFF, 8, 9, 10, 11, (char)0xFF, 12,
358
0
        (char)0xFF, (char)0xFF, (char)0xFF, (char)0xFF, 0, 1, 2, 3,
359
0
        (char)0xFF, 4, 5, 6, 7, (char)0xFF, 8, 9);
360
0
    __m256i mask_5_bytes = _mm256_setr_epi8(0, 0, 0, 0, (char)0xFF, 0, 0, 0, 0, (char)0xFF,
361
0
        0, 0, 0, 0, (char)0xFF, 0, 0, 0, 0, (char)0xFF,
362
0
        0, 0, 0, 0, (char)0xFF, 0, 0, 0, 0, (char)0xFF,
363
0
        0, 0);
364
0
    __m256i shuffled_4_bytes = _mm256_shuffle_epi8(v0, shuffling_mask);
365
0
    __m256i v0_w_nl = insert_newlines_by_mask(shuffled_4_bytes, mask_5_bytes);
366
367
0
    _mm256_storeu_si256((__m256i *)(output + 0), v0_w_nl);
368
369
    /* Handle cross-lane remainder logic */
370
    /* Without macros, _mm256_srli_si256 complains that the last arg must be an 8-bit immediate */
371
0
#define B_LANE 16 /* Bytes per lane */
372
0
#define N_RET_1_L 3 /* bytes "shifted out" of lane 0 */
373
0
#define N_RET_2_L (N_RET_1_L + 4) /* bytes "shifted out" of lane 1 */
374
375
    /* Bytes that were shifted out of lane 0 */
376
0
    __m256i rem_1_L = _mm256_srli_si256(v0, B_LANE - N_RET_1_L);
377
378
    /* Bytes that were shifted out of lane 1 */
379
0
    __m256i rem_2_L_P1 = _mm256_srli_si256(_mm256_slli_si256(_mm256_srli_si256(v0, B_LANE - N_RET_2_L),
380
0
                                               B_LANE - N_RET_1_L),
381
0
        B_LANE - 2);
382
383
    /* isolate the bytes that were shifted out of lane 1 */
384
0
    __m256i rem_2_L_P2 = _mm256_slli_si256(
385
0
        _mm256_srli_si256(v0,
386
0
            B_LANE - N_RET_2_L + N_RET_1_L),
387
0
        N_RET_1_L);
388
389
0
    __m256i rem_2_L = _mm256_or_si256(rem_2_L_P1, rem_2_L_P2);
390
391
0
    int32_t rem_1_L_ext = _mm256_extract_epi32(rem_1_L, 0);
392
0
    int64_t rem_2_L_ext = _mm256_extract_epi64(rem_2_L, 2);
393
394
0
    uint8_t *out = output + 16;
395
0
    memcpy(out, &rem_1_L_ext, sizeof(rem_1_L_ext));
396
0
    out += 3;
397
0
    *out++ = '\n';
398
399
0
    out = output + 32;
400
0
    memcpy(out, &rem_2_L_ext, sizeof(rem_2_L_ext));
401
0
    out += 2;
402
0
    *out++ = '\n';
403
0
    out += 4;
404
0
    *out++ = '\n';
405
406
0
    size_t written = (out - output);
407
0
    return written;
408
0
}
409
OPENSSL_UNTARGET_AVX2
410
411
OPENSSL_TARGET_AVX2
412
static ossl_inline size_t insert_nl_str8(const __m256i v0, uint8_t *output)
413
0
{
414
0
    __m256i shuffling_mask = _mm256_setr_epi8(0, 1, 2, 3, 4, 5, 6, 7, (char)0xFF,
415
0
        8, 9, 10, 11, 12, 13, 14,
416
0
        (char)0xFF, (char)0xFF, 0, 1, 2, 3, 4, 5, 6,
417
0
        7, (char)0xFF, 8, 9, 10, 11, 12);
418
0
    __m256i shuffled_4_bytes = _mm256_shuffle_epi8(v0, shuffling_mask);
419
0
    _mm256_storeu_si256((__m256i *)(output), shuffled_4_bytes);
420
0
    int8_t rem_1_L = _mm256_extract_epi8(v0, 15);
421
0
    int8_t rem_2_L_P1 = _mm256_extract_epi8(v0, 29);
422
0
    int16_t rem_2_L_P2 = _mm256_extract_epi16(v0, 15);
423
0
    uint8_t *out = output;
424
425
0
    memcpy(out + 16, &rem_1_L, sizeof(rem_1_L));
426
0
    memcpy(out + 32, &rem_2_L_P1, sizeof(rem_2_L_P1));
427
0
    memcpy(out + 32 + 1, &rem_2_L_P2, sizeof(rem_2_L_P2));
428
429
0
    output[8] = '\n';
430
0
    output[17] = '\n';
431
0
    output[26] = '\n';
432
0
    output[35] = '\n';
433
434
0
    out += 32 + 4;
435
436
0
    size_t written = (out - output);
437
0
    return written;
438
0
}
439
OPENSSL_UNTARGET_AVX2
440
441
OPENSSL_TARGET_AVX2
442
size_t encode_base64_avx2(EVP_ENCODE_CTX *ctx, unsigned char *dst,
443
    const unsigned char *src, int srclen, int ctx_length,
444
    int *final_wrap_cnt)
445
0
{
446
0
    const uint8_t *input = (const uint8_t *)src;
447
0
    uint8_t *out = (uint8_t *)dst;
448
0
    int i = 0;
449
0
    int stride = (ctx == NULL) ? 0 : ctx_length / 3 * 4;
450
0
    int wrap_cnt = 0;
451
0
    const int use_srp = (ctx != NULL
452
0
        && (ctx->flags & EVP_ENCODE_CTX_USE_SRP_ALPHABET) != 0);
453
0
    const __m256i shuf = _mm256_set_epi8(10, 11, 9, 10, 7, 8, 6, 7, 4, 5, 3, 4, 1, 2, 0, 1,
454
0
        10, 11, 9, 10, 7, 8, 6, 7, 4, 5, 3, 4, 1, 2, 0, 1);
455
0
    int base = 0;
456
457
    /* Process 96 bytes at a time */
458
0
    for (; i + 100 <= srclen; i += 96) {
459
0
        _mm_prefetch((const char *)(input + i + 192), _MM_HINT_T0);
460
        /*
461
         * Interleaved for each vector: load, shuffle, bit-split, lookup
462
         * before starting the next, giving the OoO engine independent work chains
463
         * across execution ports.
464
         */
465
0
        const __m128i lo0 = _mm_loadu_si128((const __m128i *)(input + i + 4 * 3 * 0));
466
0
        const __m128i hi0 = _mm_loadu_si128((const __m128i *)(input + i + 4 * 3 * 1));
467
0
        __m256i in0 = _mm256_shuffle_epi8(_mm256_set_m128i(hi0, lo0), shuf);
468
0
        const __m256i t0_0 = _mm256_and_si256(in0, _mm256_set1_epi32(0x0fc0fc00));
469
0
        const __m256i t1_0 = _mm256_mulhi_epu16(t0_0, _mm256_set1_epi32(0x04000040));
470
0
        const __m256i t2_0 = _mm256_and_si256(in0, _mm256_set1_epi32(0x003f03f0));
471
0
        const __m256i t3_0 = _mm256_mullo_epi16(t2_0, _mm256_set1_epi32(0x01000010));
472
0
        const __m256i input0 = _mm256_or_si256(t1_0, t3_0);
473
474
0
        const __m128i lo1 = _mm_loadu_si128((const __m128i *)(input + i + 4 * 3 * 2));
475
0
        const __m128i hi1 = _mm_loadu_si128((const __m128i *)(input + i + 4 * 3 * 3));
476
0
        __m256i in1 = _mm256_shuffle_epi8(_mm256_set_m128i(hi1, lo1), shuf);
477
0
        const __m256i t0_1 = _mm256_and_si256(in1, _mm256_set1_epi32(0x0fc0fc00));
478
0
        const __m256i t1_1 = _mm256_mulhi_epu16(t0_1, _mm256_set1_epi32(0x04000040));
479
0
        const __m256i t2_1 = _mm256_and_si256(in1, _mm256_set1_epi32(0x003f03f0));
480
0
        const __m256i t3_1 = _mm256_mullo_epi16(t2_1, _mm256_set1_epi32(0x01000010));
481
0
        const __m256i input1 = _mm256_or_si256(t1_1, t3_1);
482
483
0
        const __m128i lo2 = _mm_loadu_si128((const __m128i *)(input + i + 4 * 3 * 4));
484
0
        const __m128i hi2 = _mm_loadu_si128((const __m128i *)(input + i + 4 * 3 * 5));
485
0
        __m256i in2 = _mm256_shuffle_epi8(_mm256_set_m128i(hi2, lo2), shuf);
486
0
        const __m256i t0_2 = _mm256_and_si256(in2, _mm256_set1_epi32(0x0fc0fc00));
487
0
        const __m256i t1_2 = _mm256_mulhi_epu16(t0_2, _mm256_set1_epi32(0x04000040));
488
0
        const __m256i t2_2 = _mm256_and_si256(in2, _mm256_set1_epi32(0x003f03f0));
489
0
        const __m256i t3_2 = _mm256_mullo_epi16(t2_2, _mm256_set1_epi32(0x01000010));
490
0
        const __m256i input2 = _mm256_or_si256(t1_2, t3_2);
491
492
0
        const __m128i lo3 = _mm_loadu_si128((const __m128i *)(input + i + 4 * 3 * 6));
493
0
        const __m128i hi3 = _mm_loadu_si128((const __m128i *)(input + i + 4 * 3 * 7));
494
0
        __m256i in3 = _mm256_shuffle_epi8(_mm256_set_m128i(hi3, lo3), shuf);
495
0
        const __m256i t0_3 = _mm256_and_si256(in3, _mm256_set1_epi32(0x0fc0fc00));
496
0
        const __m256i t1_3 = _mm256_mulhi_epu16(t0_3, _mm256_set1_epi32(0x04000040));
497
0
        const __m256i t2_3 = _mm256_and_si256(in3, _mm256_set1_epi32(0x003f03f0));
498
0
        const __m256i t3_3 = _mm256_mullo_epi16(t2_3, _mm256_set1_epi32(0x01000010));
499
0
        const __m256i input3 = _mm256_or_si256(t1_3, t3_3);
500
501
0
        __m256i vec0;
502
0
        __m256i vec1;
503
0
        __m256i vec2;
504
0
        __m256i vec3;
505
506
0
        if (use_srp) {
507
0
            vec0 = lookup_pshufb_srp(input0);
508
0
            vec1 = lookup_pshufb_srp(input1);
509
0
            vec2 = lookup_pshufb_srp(input2);
510
0
            vec3 = lookup_pshufb_srp(input3);
511
512
0
        } else {
513
0
            vec0 = lookup_pshufb_std(input0);
514
0
            vec1 = lookup_pshufb_std(input1);
515
0
            vec2 = lookup_pshufb_std(input2);
516
0
            vec3 = lookup_pshufb_std(input3);
517
0
        }
518
519
0
        if (stride == 0) {
520
0
            _mm256_storeu_si256((__m256i *)out, vec0);
521
522
0
            out += 32;
523
0
            _mm256_storeu_si256((__m256i *)out, vec1);
524
525
0
            out += 32;
526
0
            _mm256_storeu_si256((__m256i *)out, vec2);
527
528
0
            out += 32;
529
0
            _mm256_storeu_si256((__m256i *)out, vec3);
530
531
0
            out += 32;
532
0
        } else if (stride == 64) {
533
0
            _mm256_storeu_si256((__m256i *)out, vec0);
534
535
0
            out += 32;
536
0
            _mm256_storeu_si256((__m256i *)out, vec1);
537
538
0
            out += 32;
539
0
            *(out++) = '\n';
540
541
0
            _mm256_storeu_si256((__m256i *)out, vec2);
542
0
            out += 32;
543
544
0
            _mm256_storeu_si256((__m256i *)out, vec3);
545
0
            out += 32;
546
547
0
            *(out++) = '\n';
548
0
        } else if (stride == 4) {
549
0
            int out_idx = 0;
550
551
0
            out_idx += (int)insert_nl_str4(vec0, out + out_idx);
552
0
            out_idx += (int)insert_nl_str4(vec1, out + out_idx);
553
0
            out_idx += (int)insert_nl_str4(vec2, out + out_idx);
554
0
            out_idx += (int)insert_nl_str4(vec3, out + out_idx);
555
556
0
            out += out_idx;
557
0
        } else if (stride == 8) {
558
559
0
            out += insert_nl_str8(vec0, out);
560
0
            out += insert_nl_str8(vec1, out);
561
0
            out += insert_nl_str8(vec2, out);
562
0
            out += insert_nl_str8(vec3, out);
563
564
0
        } else if (stride == 12) {
565
0
            switch (base) {
566
0
            case 0:
567
568
0
                out += insert_nl_gt16(vec0, out, stride, &wrap_cnt);
569
0
                out += insert_nl_2nd_vec_stride_12(vec1, out, stride, &wrap_cnt);
570
0
                out += insert_nl_gt16(vec2, out, stride, &wrap_cnt);
571
0
                out += insert_nl_gt16(vec3, out, stride, &wrap_cnt);
572
0
                break;
573
0
            case 1:
574
0
                out += insert_nl_2nd_vec_stride_12(vec0, out, stride, &wrap_cnt);
575
0
                out += insert_nl_gt16(vec1, out, stride, &wrap_cnt);
576
0
                out += insert_nl_gt16(vec2, out, stride, &wrap_cnt);
577
0
                out += insert_nl_2nd_vec_stride_12(vec3, out, stride, &wrap_cnt);
578
0
                break;
579
0
            default: /* base == 2 */
580
0
                out += insert_nl_gt16(vec0, out, stride, &wrap_cnt);
581
0
                out += insert_nl_gt16(vec1, out, stride, &wrap_cnt);
582
0
                out += insert_nl_2nd_vec_stride_12(vec2, out, stride, &wrap_cnt);
583
0
                out += insert_nl_gt16(vec3, out, stride, &wrap_cnt);
584
0
                break;
585
0
            }
586
587
0
            if (++base == 3)
588
0
                base = 0;
589
0
        } else if (stride >= 32) {
590
0
            out += ins_nl_gt32(vec0, out, stride, &wrap_cnt);
591
0
            out += ins_nl_gt32(vec1, out, stride, &wrap_cnt);
592
0
            out += ins_nl_gt32(vec2, out, stride, &wrap_cnt);
593
0
            out += ins_nl_gt32(vec3, out, stride, &wrap_cnt);
594
0
        } else if (stride >= 16) {
595
0
            out += insert_nl_gt16(vec0, out, stride, &wrap_cnt);
596
0
            out += insert_nl_gt16(vec1, out, stride, &wrap_cnt);
597
0
            out += insert_nl_gt16(vec2, out, stride, &wrap_cnt);
598
0
            out += insert_nl_gt16(vec3, out, stride, &wrap_cnt);
599
0
        }
600
0
    }
601
602
0
    if (stride == 0) {
603
0
        for (; i + 28 <= srclen; i += 24) {
604
            /* lo = [xxxx|DDDC|CCBB|BAAA] */
605
            /* hi = [xxxx|HHHG|GGFF|FEEE] */
606
0
            const __m128i lo = _mm_loadu_si128((const __m128i *)(input + i));
607
0
            const __m128i hi = _mm_loadu_si128((const __m128i *)(input + i + 4 * 3));
608
            /*
609
             * bytes from groups A, B and C are needed in separate 32-bit lanes
610
             * in = [0HHH|0GGG|0FFF|0EEE[0DDD|0CCC|0BBB|0AAA]
611
             */
612
0
            __m256i in = _mm256_shuffle_epi8(_mm256_set_m128i(hi, lo), shuf);
613
0
            const __m256i t0 = _mm256_and_si256(in, _mm256_set1_epi32(0x0fc0fc00));
614
0
            const __m256i t1 = _mm256_mulhi_epu16(t0, _mm256_set1_epi32(0x04000040));
615
0
            const __m256i t2 = _mm256_and_si256(in, _mm256_set1_epi32(0x003f03f0));
616
0
            const __m256i t3 = _mm256_mullo_epi16(t2, _mm256_set1_epi32(0x01000010));
617
0
            const __m256i indices = _mm256_or_si256(t1, t3);
618
0
            _mm256_storeu_si256((__m256i *)out, (use_srp ? lookup_pshufb_srp : lookup_pshufb_std)(indices));
619
620
0
            out += 32;
621
0
        }
622
0
    }
623
0
    *final_wrap_cnt = wrap_cnt;
624
625
0
    if (stride >= 32 && wrap_cnt == stride) {
626
0
        wrap_cnt = 0;
627
0
        *out++ = '\n';
628
0
    }
629
630
0
    return (size_t)(out - (uint8_t *)dst) + evp_encodeblock_int(ctx, out, src + i, srclen - i, final_wrap_cnt);
631
0
}
632
OPENSSL_UNTARGET_AVX2
633
#endif /* HAVE_AVX2 */