// These instructions multiply a 2x8 matrix (samples) by an 8x2 matrix // (filter), destructively accumulating into the destination register.
int32x4_t sum = vusmmlaq_s32(vdupq_n_s32(0), perm_samples, filters);
// Tap 0, as well as further narrowing and packing, is applied by the caller. return vmovn_s32(sum);
}
// These instructions multiply a 2x8 matrix (samples) by an 8x2 matrix // (filter), destructively accumulating into the destination register.
int32x4_t sum0123 = vusmmlaq_s32(vdupq_n_s32(0), perm_samples[0], filters);
int32x4_t sum4567 = vusmmlaq_s32(vdupq_n_s32(0), perm_samples[1], filters);
// Narrow and re-pack.
int16x8_t sum = vcombine_s16(vmovn_s32(sum0123), vmovn_s32(sum4567)); // Apply tap 0 and accumulate.
sum = vreinterpretq_s16_u16(
vmlsl_u8(vreinterpretq_u16_s16(sum), vget_low_u8(samples), f0));
// We halved the filter values so -1 from right shift. return vqrshrun_n_s16(sum, FILTER_BITS - 1);
}
staticinlinevoid convolve8_horiz_8tap_neon_i8mm( const uint8_t *src, ptrdiff_t src_stride, uint8_t *dst,
ptrdiff_t dst_stride, const int16_t *filter_x, int w, int h) { // Filter values are even, so halve to reduce intermediate precision reqs. const int8x8_t filter_s8 = vshrn_n_s16(vld1q_s16(filter_x), 1); // Stagger the filter for use with the matrix multiply instructions. // { f1, f2, f3, f4, f5, f6, f7, 0, 0, f1, f2, f3, f4, f5, f6, f7 } const uint8x16_t filter_idx = vld1q_u8(kFilterPermuteTbl); const int8x16_t filter =
vqtbl1q_s8(vcombine_s8(filter_s8, vdup_n_s8(0)), filter_idx);
// Since f0 is always negative and samples are unsigned, subtract (unsigned) // s0 * -f0 to avoid signed overflow. const uint8x8_t f0 = vdup_n_u8(-filter_x[0] >> 1);
if (w == 4) { const uint8x16_t perm_tbl = vld1q_u8(kMatMul8PermuteTbl);
// These instructions multiply a 2x8 matrix (samples) by an 8x2 matrix // (filter), destructively accumulating into the destination register.
int32x4_t sum = vusmmlaq_s32(vdupq_n_s32(0), perm_samples, filter);
// Further narrowing and packing is performed by the caller. return vmovn_s32(sum);
}
// These instructions multiply a 2x8 matrix (samples) by an 8x2 matrix // (filter), destructively accumulating into the destination register.
int32x4_t sum0123 = vusmmlaq_s32(vdupq_n_s32(0), perm_samples[0], filter);
int32x4_t sum4567 = vusmmlaq_s32(vdupq_n_s32(0), perm_samples[1], filter);
// Narrow and re-pack.
int16x8_t sum = vcombine_s16(vmovn_s32(sum0123), vmovn_s32(sum4567)); // We halved the filter values so -1 from right shift. return vqrshrun_n_s16(sum, FILTER_BITS - 1);
}
staticinlinevoid convolve8_horiz_6tap_neon_i8mm( const uint8_t *src, ptrdiff_t src_stride, uint8_t *dst,
ptrdiff_t dst_stride, const int16_t *filter_x, int width, int height) { // Filter values are even, so halve to reduce intermediate precision reqs. const int8x8_t x_filter = vshrn_n_s16(vld1q_s16(filter_x), 1); // Stagger the filter for use with the matrix multiply instructions. // { f0, f1, f2, f3, f4, f5, 0, 0, 0, f0, f1, f2, f3, f4, f5, 0 } const int8x16_t filter =
vcombine_s8(vext_s8(x_filter, x_filter, 1), x_filter);
// Narrow and re-pack.
int16x8_t sum = vcombine_s16(vmovn_s32(sum0), vmovn_s32(sum1)); // We halved the filter values so -1 from right shift. return vqrshrun_n_s16(sum, FILTER_BITS - 1);
}
staticinlinevoid convolve8_vert_8tap_neon_i8mm( const uint8_t *src, ptrdiff_t src_stride, uint8_t *dst,
ptrdiff_t dst_stride, const int16_t *filter_y, int w, int h) { // Filter values are even, so halve to reduce intermediate precision reqs. const int8x8_t filter = vshrn_n_s16(vld1q_s16(filter_y), 1); const uint8x16x3_t merge_block_tbl = vld1q_u8_x3(kDotProdMergeBlockTbl);
uint8x16x2_t samples_LUT;
// Prepare block for next iteration - re-using as much as possible. // Shuffle everything up four rows.
s0123 = s4567;
s1234 = s5678;
s2345 = s6789;
s3456 = s78910;
src += 4 * src_stride;
dst += 4 * dst_stride;
h -= 4;
} while (h != 0);
} else { do { int height = h; const uint8_t *s = src;
uint8_t *d = dst;
// Prepare block for next iteration - re-using as much as possible. // Shuffle everything up four rows.
s0123_lo = s4567_lo;
s0123_hi = s4567_hi;
s1234_lo = s5678_lo;
s1234_hi = s5678_hi;
s2345_lo = s6789_lo;
s2345_hi = s6789_hi;
s3456_lo = s78910_lo;
s3456_hi = s78910_hi;
s += 4 * src_stride;
d += 4 * dst_stride;
height -= 4;
} while (height != 0);
src += 8;
dst += 8;
w -= 8;
} while (w != 0);
}
}
staticinline int16x4_t convolve4_4_v(const uint8x16_t samples, const int8x8_t filters) { // Sample permutation is performed by the caller.
int32x4_t sum = vusdotq_lane_s32(vdupq_n_s32(0), samples, filters, 0);
// Further narrowing and packing is performed by the caller. return vmovn_s32(sum);
}
staticinline uint8x8_t convolve4_8_v(const uint8x16_t samples0, const uint8x16_t samples1, const int8x8_t filters) { // Sample permutation is performed by the caller.
// Narrow and re-pack.
int16x8_t sum = vcombine_s16(vmovn_s32(sum0), vmovn_s32(sum1)); // We halved the filter values so -1 from right shift. return vqrshrun_n_s16(sum, FILTER_BITS - 1);
}
// This operation combines a conventional transpose and the sample permute // required before computing the dot product.
uint8x16_t s0123;
transpose_concat_elems_u8_4x4(s0, s1, s2, s3, &s0123);
// This operation combines a conventional transpose and the sample permute // required before computing the dot product.
uint8x16_t s0123_lo, s0123_hi;
transpose_concat_elems_u8_8x4(s0, s1, s2, s3, &s0123_lo, &s0123_hi);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.