[英]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.