簡體   English   中英

按字節填充xmm寄存器

[英]Filling xmm register bytewise

我需要計算存儲在一個數組中的32個uint8t值的平均值。 出於性能原因,我想更改以下代碼以使用pavgb命令和xmm寄存器。 問題是我無法使用movdqu一次復制16字節,因為我在循環中進行了一些計算以獲得平均值。 下面的代碼是我正在使用的實際代碼的簡化版本。

;
; void average(uint8_t *res, uint8_t *input)
;    rdi = res   | res holds 16 values
;    rsi = input | input holds 32 values
;
segment .text
    global average

average:    
    mov rcx, 0
    xor rax, rax
    xor rbx, rbx
.loop
    mov al, [rsi + rcx]
    cmp al, 16
    jge .endif
    add al, 16

    .endif
    mov bl, [rsi + rcx + 16]
    cmp bl, 16
    jge .endif2
    add bl, 16

    .endif2
    add ax, bl
    shr ax, 1

    mov [rdi], al

    inc rdi
    inc rsi
    inc rcx

    cmp rcx, 16
    jl .loop 

因此,更改代碼以與xmm寄存器一起使用,以便最終可以做類似的事情:

pavgb   xmm0, xmm1
movdqu  [rdi], xmm0

我需要按字節填充xmm0和xmm1寄存器。 有沒有辦法使這項工作?

使用pavgb指令實際上沒有任何意義,因為設置pavgb所需的額外工作遠遠超出了首先使用pavgb的性能優勢。 您現有的代碼很好。

即使使用了優化的SSE版本,該功能仍然太短,以至於性能可能會被函數調用開銷所淹沒。

為了獲得性能優勢,您可能需要使用內部函數,以便編譯器可以理解代碼並將其合並到自己的優化中(例如,內聯)。

void average(uint8_t *res, uint8_t *input)
{
    auto boundary = __m128i _mm_set1_epi8(0x10);

    // Process the first half
    auto part1 = _mm_loadu_si128((__m128i *)input);
    auto adjust1 = _mm_and_si128(_mm_pcmpgt_epi8(boundary, part1), boundary);
    auto adjusted1 = _mm_add_epi8(part1, adjust1);

   // process the second half
    auto part2 = _mm_loadu_si128((__m128i *)(input + 16);
    auto adjust2 = _mm_and_si128(_mm_pcmpgt_epi8(boundary, part2), boundary);
    auto adjusted2 = _mm_add_epi8(part2, adjust2);

   // average them together
   auto result = _mm_avg_epu8(adjusted1, adjusted2);

   // save the answer
   _mm_storeu_si128((__m128i *)res, result);
}

為了獲得更好的性能,您可能希望函數直接返回__m128i ,以便調用者可以立即使用它進行計算,而不必從內存中讀取結果。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM