Итак, стандарт POSIX.1-2001 дает нам отличную для этого функцию - swab, в glibc 2.5 реализована она следующим образом:
void
swab (const void *bfrom, void *bto, ssize_t n)
{
const char *from = (const char *) bfrom;
char *to = (char *) bto;
n &= ~((ssize_t) 1);
while (n > 1)
{
const char b0 = from[--n], b1 = from[--n];
to[n] = b0;
to[n + 1] = b1;
}
}
По моим замерам в моей системе реализация, с эталонным количеством 51.2 мегабайт мусора, справляется в среднем за 110744 миллионных долей секунды.
Но так как просто так было не интересно, а в списке рассылок libdc1394-devel была год назад была обсуждена эта проблема и промелькнуло слово SSE2 ( кстати, новая спецификация IIDC позволит в теории указывать порядок байтов, только где-же таких камер взять нам? ), мой вариант написанный сегодня с использованием SSE2:
void swab_sse2(const void *from, void *to, ssize_t n) {
const char xmm_mask_1[] __attribute__ ((aligned(16))) = {0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff};
const char xmm_mask_2[] __attribute__ ((aligned(16))) = {0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00};
const char *cfrom = (const char *) from;
char *cto = (char *) to;
asm("\
movapd (%0),%%xmm2; \n\
movapd (%1),%%xmm3; \n\
" :
: "r" (xmm_mask_1), "r" (xmm_mask_2)
);
ssize_t i = 0;
while( i < n && ( n - i ) >= 16 ){
asm("\
movupd (%0),%%xmm0; \n\
movapd %%xmm0,%%xmm1; \n\
pslldq $1,%%xmm0; \n\
psrldq $1,%%xmm1; \n\
andpd %%xmm2,%%xmm0; \n\
andpd %%xmm3,%%xmm1; \n\
orpd %%xmm0,%%xmm1; \n\
movupd %%xmm1,(%1); \n\
" :
: "r" (from + i), "r" ( to + i ) );
i += 16;
}
while ( i < n && ( n - i ) >= 2 ){
const char b0 = cfrom[i++], b1 = cfrom[i++];
cto[i - 1] = b0;
cto[i - 2] = b1;
}
}
Компилятору gcc надо скормить -msse2, для компиляции безобразия. Работает в среднем за 98323 миллионных секунды. откуда делаем вывод, что никакого толка в этой затее нет, а происходит некое соревнование меня и оптимизатора gcc :)
p.s. На ассемблере писал первый раз в жизни... и больше не буду )
update: только вчера заметил, что можно обойтись тремя регистрами вместо четырех.
Комментариев нет:
Отправить комментарий