- 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
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
// https://github.com/google/ruy/blob/2887692065c38ef6617f423feafc6b69dd0a0681/ruy/pack_avx2_fma.cc#L66
inline void Pack8bitColMajorForAvx2Packer(
const std::int8_t* src_ptr, std::int8_t input_xor,
const std::int8_t* zerobuf, int src_stride, int remaining_src_cols,
int src_rows, std::int8_t* packed_ptr, std::int32_t* sums_ptr,
std::int8_t* trailing_buf) {
using Layout = PackImpl8bitAvx2::Layout;
RUY_DCHECK_EQ(Layout::kCols, 8);
RUY_DCHECK_EQ(Layout::kRows, 4);
// Each Layout::Rows is 4 contiguous input, contiguous packed elements.
// We process 8 of these chunks at a time, padding short input chunks.
constexpr int kNumRowChunks = 8;
constexpr int kNumChunkedSrcRows = kNumRowChunks * Layout::kRows;
const std::int8_t* src_ptr0 = src_ptr;
const std::int8_t* src_ptr1 = src_ptr0 + src_stride;
const std::int8_t* src_ptr2 = src_ptr1 + src_stride;
const std::int8_t* src_ptr3 = src_ptr2 + src_stride;
const std::int8_t* src_ptr4 = src_ptr3 + src_stride;
const std::int8_t* src_ptr5 = src_ptr4 + src_stride;
const std::int8_t* src_ptr6 = src_ptr5 + src_stride;
const std::int8_t* src_ptr7 = src_ptr6 + src_stride;
std::int64_t src_inc0 = kNumChunkedSrcRows;
std::int64_t src_inc1 = kNumChunkedSrcRows;
std::int64_t src_inc2 = kNumChunkedSrcRows;
std::int64_t src_inc3 = kNumChunkedSrcRows;
std::int64_t src_inc4 = kNumChunkedSrcRows;
std::int64_t src_inc5 = kNumChunkedSrcRows;
std::int64_t src_inc6 = kNumChunkedSrcRows;
std::int64_t src_inc7 = kNumChunkedSrcRows;
// Handle cases where source does not have Layout::kCols (8) columns.
if (remaining_src_cols < 8) {
if (remaining_src_cols <= 0) {
src_ptr0 = zerobuf;
src_inc0 = 0;
}
if (remaining_src_cols <= 1) {
src_ptr1 = zerobuf;
src_inc1 = 0;
}
if (remaining_src_cols <= 2) {
src_ptr2 = zerobuf;
src_inc2 = 0;
}
if (remaining_src_cols <= 3) {
src_ptr3 = zerobuf;
src_inc3 = 0;
}
if (remaining_src_cols <= 4) {
src_ptr4 = zerobuf;
src_inc4 = 0;
}
if (remaining_src_cols <= 5) {
src_ptr5 = zerobuf;
src_inc5 = 0;
}
if (remaining_src_cols <= 6) {
src_ptr6 = zerobuf;
src_inc6 = 0;
}
src_ptr7 = zerobuf;
src_inc7 = 0;
}
const std::int8_t zero_point = zerobuf[0];
if (sums_ptr) {
// i: Layout::kCols.
for (int i = 0; i < 8; ++i) {
sums_ptr[i] = 0;
}
}
std::int32_t sums_adjustment = 0;
const __m256i ones_16bit = _mm256_set1_epi16(1);
__m256i sums_4x2_32bit_lo = _mm256_set1_epi32(0);
__m256i sums_4x2_32bit_hi = _mm256_set1_epi32(0);
// The overall packing effectively pads the source rows to
// (src_rows + 63) & ~63. The iteration over k may skip when m=1, and then we
// only pack for (src_rows + 31) & ~31. When there is an incomplete
// destination block, this is stored into trailing_buf instead of packed_ptr.
for (int k = 0; k < src_rows; k += kNumChunkedSrcRows) {
// Available source rows.
// If this is less than 0 (for m=1), we skip, having filled trailing
// buffer for m=0. Also, if source rows is zero on m=1, then we filled
// exactly to the end of the column in the packed buffer.
const int available_src_rows = src_rows - k;
// Effectively,
// available rows = std::max(0, std::min(8, src_rows - k));
// treat each case separately.
if (available_src_rows >= kNumChunkedSrcRows) {
if (sums_ptr) {
__m256i t0, t1, t2, t3, t4, t5, t6, t7;
__m256i r0, r1, r2, r3, r4, r5, r6, r7;
const __m256i input_xor_v = _mm256_set1_epi8(input_xor);
t0 = _mm256_loadu_si256(reinterpret_cast<const __m256i*>(src_ptr0));
t4 = _mm256_loadu_si256(reinterpret_cast<const __m256i*>(src_ptr4));
t1 = _mm256_loadu_si256(reinterpret_cast<const __m256i*>(src_ptr1));
И почему они эту комбинатушню не хотят генерить шаблоноговном? И вообще, по какому, блядь, принципу расставлена эта хуйня?
почему сначала
r0 = _mm256_unpacklo_epi32(t0, t1);
потом
r4 = _mm256_unpacklo_epi32(t4, t5);
потом
r2 = _mm256_unpackhi_epi32(t0, t1);
???
r0 – нулевой оффсет «регистра», потом оттуда два байта высасывают и переходят в следующий «регистр» за lo частью. Потом из предыдущего берут hi.
В принципе, адекватный низкоуровневый код. Когда я cpuid использовал, я тоже написал правильно, как я думал, а потом оказалось, что буквы в другом порядке. Но я долго не разбирался и просто переставил блоки кода, получилось примерно так же непонятно.
Ну х.з., инканус вроде слишком стар чтобы лабы про cpuid пилить.