...Было время, когда ассемблерные вставки для CPU действительно имели смысл...
ну почему тогда функции strcpy, memset, ... оптимизировали Inline Assembler (встроенным ассемблером)?
впрочем неуместно будет здесь отстаивать эту точку зрения!
ну что же давай начнём сначала.
понятно что можно писать на асме, но в таком случае причем тут C++
стоимость поддержки решения сильно возрастает, приходится поддерживать код для кучу компиляторов разом (это мой случай)
я совершенно не против асма когда это действительно необходимо
что касается memcpy
то эта функция максимально приближена по своей сути к железу, а не к прикладной логике, к тому же она может быть реализована на асме всего парой строк.
и как справедливо заметил Finch не всегда она реализована на asm.
есть еще один не приятный момент во вставке asm, компилятор долго выстраивал команды, прореживал их nop`ами менял операции местами, что бы максимально наполнить конвейеры процессора, а тут ты весь такой на белом коне и в шляпе, одну маленькую инструкцию встраиваешь она же "быстрая", при этом разрушаешь порядок команд и часть конвейеров процессора пару тактов отрабатывают в холостую.
повторил тест на работе в студии по младше но зато не Express (в которой нет кое-каких опций сборки)
Blend time=16360
Blend time=15109
BlendAsm time=18265
BlendAsm time=19625
чувствуешь разницу? asm проигрывает.
это то что сгеренерировал сам компилятор:
unsigned int Blend(unsigned int dst, unsigned int src, unsigned int alpha)
{
unsigned int dstRB = (dst & 0x00ff00ff);
00401000 mov eax,dword ptr [esp+4]
unsigned int dstG = (dst & 0x0000ff00);
unsigned int rb = (src & 0x00ff00ff) - dstRB;
00401004 mov ecx,dword ptr [esp+8]
00401008 mov edx,eax
0040100A and eax,0FF00h
0040100F push esi
00401010 mov esi,eax
00401012 mov eax,ecx
00401014 and eax,0FF00FFh
unsigned int g = (src & 0x0000ff00) - dstG;
00401019 and ecx,0FF00h
0040101F sub ecx,esi
00401021 push edi
rb *= alpha;
00401022 mov edi,dword ptr [esp+14h]
00401026 and edx,0FF00FFh
g *= alpha;
0040102C imul ecx,edi
0040102F sub eax,edx
00401031 imul eax,edi
rb >>= 8;
00401034 shr eax,8
g >>= 8;
00401037 shr ecx,8
rb += dstRB;
0040103A add eax,edx
g += dstG;
0040103C add ecx,esi
rb &= 0x00ff00ff;
0040103E and eax,0FF00FFh
g &= 0x0000ff00;
00401043 and ecx,0FF00h
00401049 pop edi
return (rb | g);
0040104A or eax,ecx
0040104C pop esi
};
0040104D ret
при желании можно повторить тест используя gcc и icc
опции: -mtune=pentium4 -O2
gcc (тесты выполнялись на железяке отличное от предыдущих и в RHEL5)
Blend time=10837
Blend time=10821
BlendAsm time=11623
BlendAsm time=11580
icc(подозреваю что icc переколбасил код)
Blend time=6476
Blend time=6480
BlendAsm time=6391
BlendAsm time=6370
проверяем BlandAsm cгенерированный icc
Dump of assembler code for function _Z8BlendAsmjjj:
0x080494fa <BlendAsm(unsigned int, unsigned int, unsigned int)+0>: push %edi
0x080494fb <BlendAsm(unsigned int, unsigned int, unsigned int)+1>: push %ebp
0x080494fc <BlendAsm(unsigned int, unsigned int, unsigned int)+2>: push %ebx
0x080494fd <BlendAsm(unsigned int, unsigned int, unsigned int)+3>: mov 0x10(%esp),%edx
0x08049501 <BlendAsm(unsigned int, unsigned int, unsigned int)+7>: mov 0x14(%esp),%ebp
0x08049505 <BlendAsm(unsigned int, unsigned int, unsigned int)+11>: mov 0x18(%esp),%edi
0x08049509 <BlendAsm(unsigned int, unsigned int, unsigned int)+15>: mov %edx,%ebx
0x0804950b <BlendAsm(unsigned int, unsigned int, unsigned int)+17>: and $0xff00ff,%ebx
0x08049511 <BlendAsm(unsigned int, unsigned int, unsigned int)+23>: mov %ebp,%eax
0x08049513 <BlendAsm(unsigned int, unsigned int, unsigned int)+25>: and $0xff00ff,%eax
0x08049518 <BlendAsm(unsigned int, unsigned int, unsigned int)+30>: sub %ebx,%eax
0x0804951a <BlendAsm(unsigned int, unsigned int, unsigned int)+32>: imul %edx,%eax
0x0804951d <BlendAsm(unsigned int, unsigned int, unsigned int)+35>: shr $0x8,%eax
0x08049520 <BlendAsm(unsigned int, unsigned int, unsigned int)+38>: add %ebx,%eax
0x08049522 <BlendAsm(unsigned int, unsigned int, unsigned int)+40>: and $0xff00ff,%eax
0x08049527 <BlendAsm(unsigned int, unsigned int, unsigned int)+45>: mov %edx,%ebx
0x08049529 <BlendAsm(unsigned int, unsigned int, unsigned int)+47>: and $0xff00,%ebx
0x0804952f <BlendAsm(unsigned int, unsigned int, unsigned int)+53>: mov %ebp,%ecx
0x08049531 <BlendAsm(unsigned int, unsigned int, unsigned int)+55>: and $0xff00,%ecx
0x08049537 <BlendAsm(unsigned int, unsigned int, unsigned int)+61>: sub %ebx,%ecx
0x08049539 <BlendAsm(unsigned int, unsigned int, unsigned int)+63>: imul %edi,%ecx
0x0804953c <BlendAsm(unsigned int, unsigned int, unsigned int)+66>: shr $0x8,%ecx
0x0804953f <BlendAsm(unsigned int, unsigned int, unsigned int)+69>: add %ebx,%ecx
0x08049541 <BlendAsm(unsigned int, unsigned int, unsigned int)+71>: and $0xff00,%ecx
0x08049547 <BlendAsm(unsigned int, unsigned int, unsigned int)+77>: or %ecx,%eax
0x08049549 <BlendAsm(unsigned int, unsigned int, unsigned int)+79>: mov %eax,%edx
0x0804954b <BlendAsm(unsigned int, unsigned int, unsigned int)+81>: mov %edx,%eax
0x0804954d <BlendAsm(unsigned int, unsigned int, unsigned int)+83>: pop %ebx
0x0804954e <BlendAsm(unsigned int, unsigned int, unsigned int)+84>: pop %ebp
0x0804954f <BlendAsm(unsigned int, unsigned int, unsigned int)+85>: pop %edi
0x08049550 <BlendAsm(unsigned int, unsigned int, unsigned int)+86>: ret
0x08049551 <BlendAsm(unsigned int, unsigned int, unsigned int)+87>: nop
End of assembler dump.
и наблюдаем интересную картину - icc решил, что мы не слишком сильны в кодировании на asm.
именно по этому я полагаюсь на компилятор