Hi Wathsala, I tested this on QEMU for correctness. I don't have access to any ARM environment for precise benchmarking. The only device I have is an Android phone where I can't compile DPDK either. I can isolate this code and use libbenchmark via Termux if that is needed, but I don't expect to see large measurable benefits.
This patch is based on my previous work on FFmpeg's av_crc optimization for aarch64 which you can refer here: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/21651 Thanks, Shreesh On Fri, Oct 9, 2026 at 8:54 AM Wathsala Vithanage < [email protected]> wrote: > Hi Shreesh, > > Looks correct. Can you share before and after performance data in the > commit message covering short inputs below 16 bytes, lengths exercising > the different nonzero remainders modulo 16, and larger buffers to show > the effect on the folding loop? > > Thanks > > --wathsala > > On 10/6/26 10:18, Shreesh Adiga wrote: > > This patch includes the following minor changes: > > 1) Use TBL based shift left for variable len shift instead of using > > vshift_bytes_left which adds a switch case for 16 len cases. > > 2) Align the fold constants to use PMULL and PMULL2 instructions > > instead of using cross lane operands which requires additional shift. > > 3) Remove unnecessary static arrays used in crc32_reduce_64_to_32 by > > adapting x86 SSE logic. > > 4) Use x86 SSE logic for processing partial bytes sequence to avoid > > using multiple variable len shifts which inserts switch case. > > > > Signed-off-by: Shreesh Adiga <[email protected]> > > --- > > lib/net/net_crc_neon.c | 71 +++++++++++++++++++++++++++--------------- > > 1 file changed, 46 insertions(+), 25 deletions(-) > > > > diff --git a/lib/net/net_crc_neon.c b/lib/net/net_crc_neon.c > > index d924aed25d..3833fcba6e 100644 > > --- a/lib/net/net_crc_neon.c > > +++ b/lib/net/net_crc_neon.c > > @@ -24,6 +24,31 @@ struct crc_pmull_ctx { > > alignas(16) struct crc_pmull_ctx crc32_eth_pmull; > > alignas(16) struct crc_pmull_ctx crc16_ccitt_pmull; > > > > +static const alignas(16) uint8_t crc_neon_shift_tab[32] = { > > + 0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, > > + 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0, > > + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, > > + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f > > +}; > > + > > +/** > > + * Shifts left 128 bit register by specified number of bytes > > + * > > + * @param reg > > + * 128 bit value > > + * @param num > > + * number of bytes to shift left reg by (0-16) > > + * > > + * @return > > + * reg << (num * 8) > > + */ > > +static inline uint64x2_t > > +neon_shift_left(uint64x2_t reg, const unsigned int num) > > +{ > > + uint8x16_t tbl = vld1q_u8(crc_neon_shift_tab + 16 - num); > > + return vreinterpretq_u64_u8(vqtbl1q_u8(vreinterpretq_u8_u64(reg), > tbl)); > > +} > > + > > /** > > * @brief Performs one folding round > > * > > @@ -46,12 +71,12 @@ crcr32_folding_round(uint64x2_t data_block, > uint64x2_t precomp, > > uint64x2_t fold) > > { > > uint64x2_t tmp0 = vreinterpretq_u64_p128(vmull_p64( > > - vgetq_lane_p64(vreinterpretq_p64_u64(fold), 1), > > + vgetq_lane_p64(vreinterpretq_p64_u64(fold), 0), > > vgetq_lane_p64(vreinterpretq_p64_u64(precomp), > 0))); > > > > - uint64x2_t tmp1 = vreinterpretq_u64_p128(vmull_p64( > > - vgetq_lane_p64(vreinterpretq_p64_u64(fold), 0), > > - vgetq_lane_p64(vreinterpretq_p64_u64(precomp), > 1))); > > + uint64x2_t tmp1 = vreinterpretq_u64_p128(vmull_high_p64( > > + vreinterpretq_p64_u64(fold), > > + vreinterpretq_p64_u64(precomp))); > > > > return veorq_u64(tmp1, veorq_u64(data_block, tmp0)); > > } > > @@ -98,26 +123,19 @@ static inline uint32_t > > crcr32_reduce_64_to_32(uint64x2_t data64, > > uint64x2_t precomp) > > { > > - static alignas(16) uint32_t mask1[4] = { > > - 0xffffffff, 0xffffffff, 0x00000000, 0x00000000 > > - }; > > - static alignas(16) uint32_t mask2[4] = { > > - 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff > > - }; > > uint64x2_t tmp0, tmp1, tmp2; > > > > - tmp0 = vandq_u64(data64, vld1q_u64((uint64_t *)mask2)); > > + tmp0 = vreinterpretq_u64_u32( > > + vsetq_lane_u32(0, vreinterpretq_u32_u64(data64), 0)); > > > > tmp1 = vreinterpretq_u64_p128(vmull_p64( > > vgetq_lane_p64(vreinterpretq_p64_u64(tmp0), 0), > > vgetq_lane_p64(vreinterpretq_p64_u64(precomp), 0))); > > tmp1 = veorq_u64(tmp1, tmp0); > > - tmp1 = vandq_u64(tmp1, vld1q_u64((uint64_t *)mask1)); > > > > tmp2 = vreinterpretq_u64_p128(vmull_p64( > > vgetq_lane_p64(vreinterpretq_p64_u64(tmp1), 0), > > vgetq_lane_p64(vreinterpretq_p64_u64(precomp), 1))); > > - tmp2 = veorq_u64(tmp2, tmp1); > > tmp2 = veorq_u64(tmp2, tmp0); > > > > return vgetq_lane_u32(vreinterpretq_u32_u64(tmp2), 2); > > @@ -177,10 +195,10 @@ crc32_eth_calc_pmull( > > fold = vld1q_u64((uint64_t *)buffer); > > fold = veorq_u64(fold, temp); > > if (unlikely(data_len < 4)) { > > - fold = vshift_bytes_left(fold, 8 - data_len); > > + fold = neon_shift_left(fold, 8 - data_len); > > goto barret_reduction; > > } > > - fold = vshift_bytes_left(fold, 16 - data_len); > > + fold = neon_shift_left(fold, 16 - data_len); > > goto reduction_128_64; > > } > > > > @@ -201,14 +219,17 @@ crc32_eth_calc_pmull( > > > > /** Partial bytes - process last <16 bytes */ > > if (likely(n < data_len)) { > > - uint64x2_t last16, a, b, mask; > > + uint8x16_t last16, t1, t2; > > + uint64x2_t a, b; > > uint32_t rem = data_len & 15; > > > > - last16 = vld1q_u64((const uint64_t *)&data[data_len - 16]); > > - a = vshift_bytes_left(fold, 16 - rem); > > - b = vshift_bytes_right(fold, rem); > > - mask = vshift_bytes_left(vdupq_n_u64(-1), 16 - rem); > > - b = vorrq_u64(b, vandq_u64(mask, last16)); > > + last16 = vld1q_u8((const uint8_t *)&data[data_len - 16]); > > + t1 = vld1q_u8(crc_neon_shift_tab + rem); > > + a = > vreinterpretq_u64_u8(vqtbl1q_u8(vreinterpretq_u8_u64(fold), t1)); > > + t2 = vmvnq_u8(t1); > > + t2 = vqtbl1q_u8(vreinterpretq_u8_u64(fold), t2); > > + t1 = vcgezq_s8(vreinterpretq_s8_u8(t1)); > > + b = vreinterpretq_u64_u8(vbslq_u8(t1, last16, t2)); > > > > /* k = rk3 & rk4 */ > > fold = crcr32_folding_round(b, k, a); > > @@ -230,14 +251,14 @@ void > > rte_net_crc_neon_init(void) > > { > > /* Initialize CRC16 data */ > > - uint64_t ccitt_k1_k2[2] = {0x14ff2LLU, 0x19a3cLLU}; > > - uint64_t ccitt_k3_k4[2] = {0x189aeLLU, 0x8e10LLU}; > > + uint64_t ccitt_k1_k2[2] = {0x19a3cLLU, 0x14ff2LLU}; > > + uint64_t ccitt_k3_k4[2] = {0x8e10LLU, 0x189aeLLU}; > > uint64_t ccitt_k5_k6[2] = {0x189aeLLU, 0x114aaLLU}; > > uint64_t ccitt_k7_k8[2] = {0x11c581910LLU, 0x10811LLU}; > > > > /* Initialize CRC32 data */ > > - uint64_t eth_k1_k2[2] = {0x1c6e41596LLU, 0x154442bd4LLU}; > > - uint64_t eth_k3_k4[2] = {0xccaa009eLLU, 0x1751997d0LLU}; > > + uint64_t eth_k1_k2[2] = {0x154442bd4LLU, 0x1c6e41596LLU}; > > + uint64_t eth_k3_k4[2] = {0x1751997d0LLU, 0xccaa009eLLU}; > > uint64_t eth_k5_k6[2] = {0xccaa009eLLU, 0x163cd6124LLU}; > > uint64_t eth_k7_k8[2] = {0x1f7011640LLU, 0x1db710641LLU}; > > >

