| 209 | } |
| 210 | |
| 211 | void bits_to_bytes(int64_t hardware_flags, const int num_bits, const uint8_t* bits, |
| 212 | uint8_t* bytes, int bit_offset) { |
| 213 | bits += bit_offset / 8; |
| 214 | bit_offset %= 8; |
| 215 | if (bit_offset != 0) { |
| 216 | uint64_t bits_head = bits[0] >> bit_offset; |
| 217 | int bits_in_first_byte = std::min(num_bits, 8 - bit_offset); |
| 218 | bits_to_bytes(hardware_flags, bits_in_first_byte, |
| 219 | reinterpret_cast<const uint8_t*>(&bits_head), bytes); |
| 220 | if (num_bits > bits_in_first_byte) { |
| 221 | bits_to_bytes(hardware_flags, num_bits - bits_in_first_byte, bits + 1, |
| 222 | bytes + bits_in_first_byte); |
| 223 | } |
| 224 | return; |
| 225 | } |
| 226 | |
| 227 | int num_processed = 0; |
| 228 | #if defined(ARROW_HAVE_RUNTIME_AVX2) && defined(ARROW_HAVE_RUNTIME_BMI2) |
| 229 | if ((hardware_flags & CpuInfo::AVX2) && CpuInfo::GetInstance()->HasEfficientBmi2()) { |
| 230 | // The function call below processes whole 32 bit chunks together. |
| 231 | num_processed = num_bits - (num_bits % 32); |
| 232 | avx2::bits_to_bytes_avx2(num_processed, bits, bytes); |
| 233 | } |
| 234 | #endif |
| 235 | // Processing 8 bits at a time |
| 236 | constexpr int unroll = 8; |
| 237 | for (int i = num_processed / unroll; i < num_bits / unroll; ++i) { |
| 238 | uint8_t bits_next = bits[i]; |
| 239 | // Clear the lowest bit and then make 8 copies of remaining 7 bits, each 7 bits apart |
| 240 | // from the previous. |
| 241 | uint64_t unpacked = static_cast<uint64_t>(bits_next & 0xfe) * |
| 242 | ((1ULL << 7) | (1ULL << 14) | (1ULL << 21) | (1ULL << 28) | |
| 243 | (1ULL << 35) | (1ULL << 42) | (1ULL << 49)); |
| 244 | unpacked |= (bits_next & 1); |
| 245 | unpacked &= 0x0101010101010101ULL; |
| 246 | unpacked *= 255; |
| 247 | util::SafeStore(&reinterpret_cast<uint64_t*>(bytes)[i], unpacked); |
| 248 | } |
| 249 | int tail = num_bits % unroll; |
| 250 | if (tail) { |
| 251 | uint8_t bits_next = bits[(num_bits - tail) / unroll]; |
| 252 | // Clear the lowest bit and then make 8 copies of remaining 7 bits, each 7 bits apart |
| 253 | // from the previous. |
| 254 | uint64_t unpacked = static_cast<uint64_t>(bits_next & 0xfe) * |
| 255 | ((1ULL << 7) | (1ULL << 14) | (1ULL << 21) | (1ULL << 28) | |
| 256 | (1ULL << 35) | (1ULL << 42) | (1ULL << 49)); |
| 257 | unpacked |= (bits_next & 1); |
| 258 | unpacked &= 0x0101010101010101ULL; |
| 259 | unpacked *= 255; |
| 260 | SafeStoreUpTo8Bytes(bytes + num_bits - tail, tail, unpacked); |
| 261 | } |
| 262 | } |
| 263 | |
| 264 | void bytes_to_bits(int64_t hardware_flags, const int num_bits, const uint8_t* bytes, |
| 265 | uint8_t* bits, int bit_offset) { |
nothing calls this directly
no test coverage detected