Coverage Report

Created: 2026-07-10 07:07

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/c-blosc/blosc/bitshuffle-avx2.c
Line
Count
Source
1
/*
2
 * Bitshuffle - Filter for improving compression of typed binary data.
3
 *
4
 * Author: Kiyoshi Masui <kiyo@physics.ubc.ca>
5
 * Website: https://github.com/kiyo-masui/bitshuffle
6
 * Created: 2014
7
 *
8
 * Note: Adapted for c-blosc by Francesc Alted.
9
 *
10
 * See LICENSES/BITSHUFFLE.txt file for details about copyright and
11
 * rights to use.
12
 *
13
 */
14
15
#include "bitshuffle-generic.h"
16
#include "bitshuffle-sse2.h"
17
#include "bitshuffle-avx2.h"
18
19
20
/* Define dummy functions if AVX2 is not available for the compilation target and compiler. */
21
#if !defined(__AVX2__)
22
#include <stdlib.h>
23
24
int64_t blosc_internal_bshuf_trans_bit_elem_avx2(void* in, void* out, const size_t size,
25
                                                 const size_t elem_size, void* tmp_buf) {
26
    abort();
27
}
28
29
int64_t blosc_internal_bshuf_untrans_bit_elem_avx2(void* in, void* out, const size_t size,
30
                                                   const size_t elem_size, void* tmp_buf) {
31
    abort();
32
}
33
34
#else /* defined(__AVX2__) */
35
36
#include <immintrin.h>
37
38
/* The next is useful for debugging purposes */
39
#if 0
40
#include <stdio.h>
41
#include <string.h>
42
43
static void printymm(__m256i ymm0)
44
{
45
  uint8_t buf[32];
46
47
  ((__m256i *)buf)[0] = ymm0;
48
  printf("%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x\n",
49
          buf[0], buf[1], buf[2], buf[3],
50
          buf[4], buf[5], buf[6], buf[7],
51
          buf[8], buf[9], buf[10], buf[11],
52
          buf[12], buf[13], buf[14], buf[15],
53
          buf[16], buf[17], buf[18], buf[19],
54
          buf[20], buf[21], buf[22], buf[23],
55
          buf[24], buf[25], buf[26], buf[27],
56
          buf[28], buf[29], buf[30], buf[31]);
57
}
58
#endif
59
60
61
/* ---- Code that requires AVX2. Intel Haswell (2013) and later. ---- */
62
63
64
/* Transpose bits within bytes. */
65
static int64_t bshuf_trans_bit_byte_avx2(void* in, void* out, const size_t size,
66
81.7k
                                         const size_t elem_size) {
67
68
81.7k
    char* in_b = (char*) in;
69
81.7k
    char* out_b = (char*) out;
70
81.7k
    int32_t* out_i32;
71
72
81.7k
    size_t nbyte = elem_size * size;
73
74
81.7k
    int64_t count;
75
76
81.7k
    __m256i ymm;
77
81.7k
    int32_t bt;
78
81.7k
    size_t ii, kk;
79
80
16.5M
    for (ii = 0; ii + 31 < nbyte; ii += 32) {
81
16.4M
        ymm = _mm256_loadu_si256((__m256i *) &in_b[ii]);
82
148M
        for (kk = 0; kk < 8; kk++) {
83
131M
            bt = _mm256_movemask_epi8(ymm);
84
131M
            ymm = _mm256_slli_epi16(ymm, 1);
85
131M
            out_i32 = (int32_t*) &out_b[((7 - kk) * nbyte + ii) / 8];
86
131M
            *out_i32 = bt;
87
131M
        }
88
16.4M
    }
89
81.7k
    count = blosc_internal_bshuf_trans_bit_byte_remainder(in, out, size, elem_size,
90
81.7k
            nbyte - nbyte % 32);
91
81.7k
    return count;
92
81.7k
}
93
94
/* Transpose bits within elements. */
95
int64_t blosc_internal_bshuf_trans_bit_elem_avx2(void* in, void* out, const size_t size,
96
81.7k
                                                 const size_t elem_size, void* tmp_buf) {
97
81.7k
    int64_t count;
98
99
81.7k
    CHECK_MULT_EIGHT(size);
100
101
81.7k
    count = blosc_internal_bshuf_trans_byte_elem_sse2(in, out, size, elem_size, tmp_buf);
102
81.7k
    CHECK_ERR(count);
103
81.7k
    count = bshuf_trans_bit_byte_avx2(out, tmp_buf, size, elem_size);
104
81.7k
    CHECK_ERR(count);
105
81.7k
    count = blosc_internal_bshuf_trans_bitrow_eight(tmp_buf, out, size, elem_size);
106
107
81.7k
    return count;
108
81.7k
}
109
110
/* For data organized into a row for each bit (8 * elem_size rows), transpose
111
 * the bytes. */
112
static int64_t bshuf_trans_byte_bitrow_avx2(void* in, void* out, const size_t size,
113
27.7k
                                            const size_t elem_size) {
114
115
27.7k
    char* in_b = (char*) in;
116
27.7k
    char* out_b = (char*) out;
117
118
27.7k
    size_t nrows = 8 * elem_size;
119
27.7k
    size_t nbyte_row = size / 8;
120
27.7k
    size_t ii, jj, kk, hh, mm;
121
122
27.7k
    CHECK_MULT_EIGHT(size);
123
124
27.7k
    if (elem_size % 4)
125
26.9k
      return blosc_internal_bshuf_trans_byte_bitrow_sse2(in, out, size, elem_size);
126
127
802
    __m256i ymm_0[8];
128
802
    __m256i ymm_1[8];
129
802
    __m256i ymm_storeage[8][4];
130
131
3.94k
    for (jj = 0; jj + 31 < nbyte_row; jj += 32) {
132
8.14k
        for (ii = 0; ii + 3 < elem_size; ii += 4) {
133
25.0k
            for (hh = 0; hh < 4; hh ++) {
134
135
180k
                for (kk = 0; kk < 8; kk ++){
136
160k
                    ymm_0[kk] = _mm256_loadu_si256((__m256i *) &in_b[
137
160k
                            (ii * 8 + hh * 8 + kk) * nbyte_row + jj]);
138
160k
                }
139
140
100k
                for (kk = 0; kk < 4; kk ++){
141
80.0k
                    ymm_1[kk] = _mm256_unpacklo_epi8(ymm_0[kk * 2],
142
80.0k
                            ymm_0[kk * 2 + 1]);
143
80.0k
                    ymm_1[kk + 4] = _mm256_unpackhi_epi8(ymm_0[kk * 2],
144
80.0k
                            ymm_0[kk * 2 + 1]);
145
80.0k
                }
146
147
60.0k
                for (kk = 0; kk < 2; kk ++){
148
120k
                    for (mm = 0; mm < 2; mm ++){
149
80.0k
                        ymm_0[kk * 4 + mm] = _mm256_unpacklo_epi16(
150
80.0k
                                ymm_1[kk * 4 + mm * 2],
151
80.0k
                                ymm_1[kk * 4 + mm * 2 + 1]);
152
80.0k
                        ymm_0[kk * 4 + mm + 2] = _mm256_unpackhi_epi16(
153
80.0k
                                ymm_1[kk * 4 + mm * 2],
154
80.0k
                                ymm_1[kk * 4 + mm * 2 + 1]);
155
80.0k
                    }
156
40.0k
                }
157
158
100k
                for (kk = 0; kk < 4; kk ++){
159
80.0k
                    ymm_1[kk * 2] = _mm256_unpacklo_epi32(ymm_0[kk * 2],
160
80.0k
                            ymm_0[kk * 2 + 1]);
161
80.0k
                    ymm_1[kk * 2 + 1] = _mm256_unpackhi_epi32(ymm_0[kk * 2],
162
80.0k
                            ymm_0[kk * 2 + 1]);
163
80.0k
                }
164
165
180k
                for (kk = 0; kk < 8; kk ++){
166
160k
                    ymm_storeage[kk][hh] = ymm_1[kk];
167
160k
                }
168
20.0k
            }
169
170
45.0k
            for (mm = 0; mm < 8; mm ++) {
171
172
200k
                for (kk = 0; kk < 4; kk ++){
173
160k
                    ymm_0[kk] = ymm_storeage[mm][kk];
174
160k
                }
175
176
40.0k
                ymm_1[0] = _mm256_unpacklo_epi64(ymm_0[0], ymm_0[1]);
177
40.0k
                ymm_1[1] = _mm256_unpacklo_epi64(ymm_0[2], ymm_0[3]);
178
40.0k
                ymm_1[2] = _mm256_unpackhi_epi64(ymm_0[0], ymm_0[1]);
179
40.0k
                ymm_1[3] = _mm256_unpackhi_epi64(ymm_0[2], ymm_0[3]);
180
181
40.0k
                ymm_0[0] = _mm256_permute2x128_si256(ymm_1[0], ymm_1[1], 32);
182
40.0k
                ymm_0[1] = _mm256_permute2x128_si256(ymm_1[2], ymm_1[3], 32);
183
40.0k
                ymm_0[2] = _mm256_permute2x128_si256(ymm_1[0], ymm_1[1], 49);
184
40.0k
                ymm_0[3] = _mm256_permute2x128_si256(ymm_1[2], ymm_1[3], 49);
185
186
40.0k
                _mm256_storeu_si256((__m256i *) &out_b[
187
40.0k
                        (jj + mm * 2 + 0 * 16) * nrows + ii * 8], ymm_0[0]);
188
40.0k
                _mm256_storeu_si256((__m256i *) &out_b[
189
40.0k
                        (jj + mm * 2 + 0 * 16 + 1) * nrows + ii * 8], ymm_0[1]);
190
40.0k
                _mm256_storeu_si256((__m256i *) &out_b[
191
40.0k
                        (jj + mm * 2 + 1 * 16) * nrows + ii * 8], ymm_0[2]);
192
40.0k
                _mm256_storeu_si256((__m256i *) &out_b[
193
40.0k
                        (jj + mm * 2 + 1 * 16 + 1) * nrows + ii * 8], ymm_0[3]);
194
40.0k
            }
195
5.00k
        }
196
3.13k
    }
197
80.0k
    for (ii = 0; ii < nrows; ii ++ ) {
198
936k
        for (jj = nbyte_row - nbyte_row % 32; jj < nbyte_row; jj ++) {
199
857k
            out_b[jj * nrows + ii] = in_b[ii * nbyte_row + jj];
200
857k
        }
201
79.2k
    }
202
802
    return size * elem_size;
203
27.7k
}
204
205
206
/* Shuffle bits within the bytes of eight element blocks. */
207
static int64_t bshuf_shuffle_bit_eightelem_avx2(void* in, void* out, const size_t size,
208
27.7k
                                                const size_t elem_size) {
209
210
27.7k
    CHECK_MULT_EIGHT(size);
211
212
    /*  With a bit of care, this could be written such that such that it is */
213
    /*  in_buf = out_buf safe. */
214
27.7k
    char* in_b = (char*) in;
215
27.7k
    char* out_b = (char*) out;
216
217
27.7k
    size_t nbyte = elem_size * size;
218
27.7k
    size_t ii, jj, kk, ind;
219
220
27.7k
    __m256i ymm;
221
27.7k
    int32_t bt;
222
223
27.7k
    if (elem_size % 4) {
224
26.9k
        return blosc_internal_bshuf_shuffle_bit_eightelem_sse2(in, out, size, elem_size);
225
26.9k
    } else {
226
3.27k
        for (jj = 0; jj + 31 < 8 * elem_size; jj += 32) {
227
189k
            for (ii = 0; ii + 8 * elem_size - 1 < nbyte;
228
186k
                    ii += 8 * elem_size) {
229
186k
                ymm = _mm256_loadu_si256((__m256i *) &in_b[ii + jj]);
230
1.68M
                for (kk = 0; kk < 8; kk++) {
231
1.49M
                    bt = _mm256_movemask_epi8(ymm);
232
1.49M
                    ymm = _mm256_slli_epi16(ymm, 1);
233
1.49M
                    ind = (ii + jj / 8 + (7 - kk) * elem_size);
234
1.49M
                    * (int32_t *) &out_b[ind] = bt;
235
1.49M
                }
236
186k
            }
237
2.47k
        }
238
802
    }
239
802
    return size * elem_size;
240
27.7k
}
241
242
243
/* Untranspose bits within elements. */
244
int64_t blosc_internal_bshuf_untrans_bit_elem_avx2(void* in, void* out, const size_t size,
245
27.7k
                                                   const size_t elem_size, void* tmp_buf) {
246
247
27.7k
    int64_t count;
248
249
27.7k
    CHECK_MULT_EIGHT(size);
250
251
27.7k
    count = bshuf_trans_byte_bitrow_avx2(in, tmp_buf, size, elem_size);
252
27.7k
    CHECK_ERR(count);
253
27.7k
    count =  bshuf_shuffle_bit_eightelem_avx2(tmp_buf, out, size, elem_size);
254
255
27.7k
    return count;
256
27.7k
}
257
258
#endif /* !defined(__AVX2__) */