Implementacja kodu sumy kontrolnej dla Neon in Intrinsics

Usiłuję zaimplementować kod obliczeniowy sumy kontrolnej (dodatek uzupełnienia 2) dla NEON, używając wewnętrznego. Bieżące obliczenie sumy kontrolnej jest wykonywane na ARM.

Moja implementacja pobiera 128 bitów jednocześnie z pamięci do rejestrów NEON i wykonuje SIMD (dodawanie), a wynik jest składany do liczby 16-bitowej z 128-bitowej liczby.

Wszystko wygląda dobrze, ale moja implementacja NEON pochłania więcej czasu niż wersja ARM.

Wersja ARM wymaga:0,860000 s Wersja NEON wymaga:1.260000 s

Uwaga:

Profilowane używanie narzędzi z „time.h”Funkcja sumy kontrolnej wywołana 10 000 razy z przykładowej aplikacji i czas obliczony po pełnym uruchomieniu wszystkich funkcji

Inne szczegóły:

Użyty łańcuch narzędzi GNU (arm-none-linux-gnueabi-gcc) do kompilacji kodu wewnętrznego i nie uzbrajania łańcucha narzędzi.Platforma Linux.C-wewnętrzny kod.

Pytania:

Dlaczego wersja NEON zajmuje więcej czasu niż wersja ARM? (Chociaż zadbałem o to, aby użyto wewnętrznych z minimalnymi cyklami w partii)

Jak osiągnąć to, co chcę osiągnąć? (wydajność z NEON)

Czy ktoś mógłby mi wskazać lub udostępnić kilka przykładowych implementacji (pseudo-kod / algorytmy / kod, a nie teoretyczne dokumenty implementacyjne lub rozmowy), które wykorzystują interakcje między ARM-NEON razem?

Każda pomoc byłaby bardzo mile widziana.

Oto mój kod:

uint16_t do_csum(const unsigned char * buff, int len)
{
int odd, count, i;

uint32x4_t result = veorq_u32( result, result), sum = veorq_u32( sum, sum); 
uint16x4_t data, data_hi, data_low, data8;
uint16x8_t dataq;
uint16_t result16, disp[20] = {0,0,0,0,0,0,0,0,0,0};

if (len <= 0)
    goto out;
odd = 1 & (unsigned long) buff;
if (odd) {
    uint8x8_t data1 = veor_u8( data1, data1); 
    data1 = (uint16x4_t)vld1_lane_u8((uint8_t *)buff, data1, 0); //result = *buff << 8;
    data1 = (uint16x4_t)vshl_n_u16( data1, 8);

    len--;
    buff++;
    result = vaddw_u16(result, data1);
}
count = len >> 1;       /* nr of 16-bit words.. */
if (count) {
    if (2 & (unsigned long) buff) {
        uint16x4_t data2 = veor_u16( data2, data2); 
        data2 = (uint16x4_t) vld1_lane_u16((uint16_t *)buff, data2, 0); //result += *(unsigned short *) buff;
        count--;
        len -= 2;
        buff += 2;
        result = vaddw_u16( result, data2);
    }
    count >>= 1;        /* nr of 32-bit words.. */
    if (count) {
        if (4 & (unsigned long) buff) {
            uint32x2_t data4 = (uint16x4_t) vld1_lane_u32((uint32_t *) buff, data4, 0);
            count--;
            len -= 4;
            buff += 4;
            result = vaddw_u16( result, data4);
        }
        count >>= 1;    /* nr of 64-bit words.. */
        if (count) {
            if (8 & (unsigned long) buff) {
                uint64x1_t data8 = vld1_u64((uint64_t *) buff); 
                count--;
                len -= 8;
                buff += 8;
                result = vaddw_u16( result,(uint16x4_t)data8);
            }
            count >>= 1;    /* nr of 128-bit words.. */
            if (count) {
                do {
                    dataq = (uint16x8_t)vld1q_u64((uint64_t *) buff); // VLD1.64 {d0, d1}, [r0]
                    count--;
                    buff += 16;

                    sum = vpaddlq_u16(dataq);   
                    vst1q_u16( disp, dataq); // VST1.16 {d0, d1}, [r0]

                    result = vaddq_u32( sum, result);
                } while (count);
            }
            if (len & 8) {
                uint64x1_t data8 =  vld1_u64((uint64_t *) buff); 
                buff += 8;
                result = vaddw_u16( result, (uint16x4_t)data8);
            }
        }
        if (len & 4) {
            uint32x2_t data4 = veor_u32( data4, data4); 

            data4 = (uint16x4_t)vld1_lane_u32((uint32_t *) buff, data4, 0);//result += *(unsigned int *) buff;
            buff += 4;
            result = vaddw_u16( result,(uint16x4_t) data4);
        }
    }
    if (len & 2) {
        uint16x4_t data2 = veor_u16( data2, data2); 
        data2 = (uint16x4_t) vld1_lane_u16((uint16_t *)buff, data2, 0); //result += *(unsigned short *) buff;
        buff += 2;
        result = vaddw_u16( result, data2);
    }
}
if (len & 1){
    uint8x8_t data1 = veor_u8( data1, data1); 
    data1 = (uint16x4_t) vld1_lane_u8((uint8_t *)buff, data1, 0); //result = *buff << 8;
    result = vaddw_u8( result, data1);
}


result16 = from128to16(result);

if (odd)
    result16 = ((result16 >> 8) & 0xff) | ((result16 & 0xff) << 8);

out:
    return result16;
}

questionAnswers(1)

yourAnswerToTheQuestion