我需要计算存储在一个数组中的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寄存器。有没有办法做到这一点呢?
发布于 2015-07-21 22:59:11
使用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);
}https://stackoverflow.com/questions/31541961
复制相似问题