Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[18.221.174.248] |
|
Страницы: (5) « Первая ... 2 3 [4] 5 все ( Перейти к последнему сообщению ) |
Сообщ.
#46
,
|
|
|
applegame, а стоило ли рассчитывать, что эти варианты будут различаться?
Вот так надо: for(;x;) return false; return true; Добавлено Цитата Славян @ Это лишь говорит о том, что test короче, чем cmp. Скорость работы та же Но это лишь говорит о том, что оптимизатор понял, что test (делает AND по сути ) быстрее довольно туповатого и прямого CMP! Потому что будет cmp edi,0 (3 байта), а не cmp edi,edi (2 байта, как и test edi,edi). Добавлено При этом test edi,edi можно с тем же успехом заменить на and edi,edi или на or edi,edi. Размер тот же, скорость та же. Добавлено У меня сейчас комп не пашет (загрузился с флешки). Кто может скомпилить и прислать дизасм такого кода (для 32-х бит)? return (!x || x==0x80000000); Я поаплодирую, если там будет написано так: add edi,edi sete al Добавлено Можно ещё так попробовать: return !(x&0x7FFFFFFF); |
Сообщ.
#47
,
|
|
|
int foo(int x) { return (!x || x==0x80000000); } int bar(int x) { return !(x&0x7FFFFFFF); } _TEXT SEGMENT _x$ = 8 ; size = 4 _bar PROC ; COMDAT ; File c:\disk_f\work\100olymp\q.c ; Line 8 mov eax, DWORD PTR _x$[esp-4] and eax, 2147483647 ; 7fffffffH neg eax sbb eax, eax inc eax ; Line 9 ret 0 _bar ENDP _TEXT ENDS ; Function compile flags: /Ogtpy ; COMDAT _foo _TEXT SEGMENT _x$ = 8 ; size = 4 _foo PROC ; COMDAT ; File c:\disk_f\work\100olymp\q.c ; Line 3 mov eax, DWORD PTR _x$[esp-4] test eax, eax je SHORT $LN3@foo cmp eax, -2147483648 ; 80000000H je SHORT $LN3@foo xor eax, eax ; Line 4 ret 0 $LN3@foo: ; Line 3 mov eax, 1 ; Line 4 ret 0 _foo ENDP _TEXT ENDS _TEXT SEGMENT PARA PUBLIC FLAT 'CODE' ALIGN 16 PUBLIC _foo ; --- foo(int) _foo PROC NEAR ; parameter 1: 4 + esp .B1.1: ; Preds .B1.0 L1:: ;2.1 mov eax, DWORD PTR [4+esp] ;1.5 test eax, eax ;3.12 je .B1.3 ; Prob 50% ;3.12 ; LOE eax ebx ebp esi edi .B1.2: ; Preds .B1.1 cmp eax, -2147483648 ;3.20 jne .B1.4 ; Prob 50% ;3.20 ; LOE ebx ebp esi edi .B1.3: ; Preds .B1.2 .B1.1 mov eax, 1 ;3.12 ret ;3.12 ; LOE eax ebx ebp esi edi .B1.4: ; Preds .B1.2 xor eax, eax ;3.12 ; LOE eax ebx ebp esi edi .B1.5: ; Preds .B1.4 ret ;3.12 ALIGN 16 ; LOE ; mark_end; _foo ENDP ALIGN 16 PUBLIC _bar ; --- bar(int) _bar PROC NEAR ; parameter 1: 4 + esp .B2.1: ; Preds .B2.0 L2:: ;7.1 xor eax, eax ;8.14 mov edx, 1 ;8.14 test DWORD PTR [4+esp], 2147483647 ;8.14 cmove eax, edx ;8.14 ret ;8.14 ALIGN 16 ; LOE ; mark_end; _bar ENDP ;_bar ENDS _TEXT ENDS PUBLIC _foo PUBLIC _bar ; Function compile flags: /Ogspy ; COMDAT _bar _TEXT SEGMENT _x$ = 8 ; size = 4 _bar PROC ; COMDAT ; File c:\disk_f\work\100olymp\q.c ; Line 8 mov eax, DWORD PTR _x$[esp-4] and eax, 2147483647 ; 7fffffffH neg eax sbb eax, eax inc eax ; Line 9 ret 0 _bar ENDP _TEXT ENDS ; Function compile flags: /Ogspy ; COMDAT _foo _TEXT SEGMENT _x$ = 8 ; size = 4 _foo PROC ; COMDAT ; File c:\disk_f\work\100olymp\q.c ; Line 3 cmp DWORD PTR _x$[esp-4], 0 je SHORT $LN3@foo cmp DWORD PTR _x$[esp-4], -2147483648 ; 80000000H je SHORT $LN3@foo xor eax, eax ; Line 4 ret 0 $LN3@foo: ; Line 3 xor eax, eax inc eax ; Line 4 ret 0 _foo ENDP _TEXT ENDS _TEXT SEGMENT DWORD PUBLIC FLAT 'CODE' PUBLIC _foo ; --- foo(int) _foo PROC NEAR ; parameter 1: 4 + esp .B1.1: ; Preds .B1.0 L1:: ;2.1 mov eax, DWORD PTR [4+esp] ;1.5 test eax, eax ;3.12 je .B1.3 ; Prob 50% ;3.12 ; LOE eax ebx ebp esi edi .B1.2: ; Preds .B1.1 cmp eax, -2147483648 ;3.20 jne .B1.4 ; Prob 50% ;3.20 ; LOE ebx ebp esi edi .B1.3: ; Preds .B1.2 .B1.1 push 1 ;3.12 pop eax ;3.12 ret ;3.12 ; LOE eax ebx ebp esi edi .B1.4: ; Preds .B1.2 xor eax, eax ;3.12 ; LOE eax ebx ebp esi edi .B1.5: ; Preds .B1.4 ret ;3.12 ; LOE ; mark_end; _foo ENDP PUBLIC _bar ; --- bar(int) _bar PROC NEAR ; parameter 1: 4 + esp .B2.1: ; Preds .B2.0 L2:: ;7.1 xor eax, eax ;8.14 test DWORD PTR [4+esp], 2147483647 ;8.14 sete al ;8.14 ret ;8.14 ; LOE ; mark_end; _bar ENDP ;_bar ENDS _TEXT ENDS |
Сообщ.
#48
,
|
|
|
Цитата Qraizer @ Не надо, спасибо.64 бита приводить? Цитата Qraizer @ Вот это уже нормально test DWORD PTR [4+esp], 2147483647 ;8.14 sete al Но Intel что-то гонит. Оптимизация по размеру (приведённый чуть выше код) должна быть быстрее, ибо cmovcc медленнее, чем setcc. Интересен вариант с icl в случае, если x будет не в стеке, а в регистре... |
Сообщ.
#49
,
|
|
|
Медленнее, на такт. Но она может быть спараллелена посредством задействования обоих значений результата, тогда как setcc не может.
Добавлено Цитата Jin X @ Ок, fastcall. По скорости:Интересен вариант с icl в случае, если x будет не в стеке, а в регистре... _TEXT SEGMENT PARA PUBLIC FLAT 'CODE' ALIGN 16 PUBLIC @foo@4 ; --- foo(int) @foo@4 PROC NEAR ; parameter 1: ecx .B1.1: ; Preds .B1.0 L1:: ;2.1 test ecx, ecx ;3.12 je .B1.3 ; Prob 50% ;3.12 ; LOE ecx ebx ebp esi edi .B1.2: ; Preds .B1.1 cmp ecx, -2147483648 ;3.20 jne .B1.4 ; Prob 50% ;3.20 ; LOE ebx ebp esi edi .B1.3: ; Preds .B1.2 .B1.1 mov eax, 1 ;3.12 ret ;3.12 ; LOE eax ebx ebp esi edi .B1.4: ; Preds .B1.2 xor eax, eax ;3.12 ; LOE eax ebx ebp esi edi .B1.5: ; Preds .B1.4 ret ;3.12 ALIGN 16 ; LOE ; mark_end; @foo@4 ENDP ALIGN 16 PUBLIC @bar@4 ; --- bar(int) @bar@4 PROC NEAR ; parameter 1: ecx .B2.1: ; Preds .B2.0 L2:: ;7.1 xor eax, eax ;8.14 mov edx, 1 ;8.14 test ecx, 2147483647 ;8.14 cmove eax, edx ;8.14 ret ;8.14 ALIGN 16 ; LOE ; mark_end; @bar@4 ENDP ;@bar@4 ENDS _TEXT ENDS _TEXT SEGMENT DWORD PUBLIC FLAT 'CODE' PUBLIC @foo@4 ; --- foo(int) @foo@4 PROC NEAR ; parameter 1: ecx .B1.1: ; Preds .B1.0 L1:: ;2.1 test ecx, ecx ;3.12 je .B1.3 ; Prob 50% ;3.12 ; LOE ecx ebx ebp esi edi .B1.2: ; Preds .B1.1 cmp ecx, -2147483648 ;3.20 jne .B1.4 ; Prob 50% ;3.20 ; LOE ebx ebp esi edi .B1.3: ; Preds .B1.2 .B1.1 push 1 ;3.12 pop eax ;3.12 ret ;3.12 ; LOE eax ebx ebp esi edi .B1.4: ; Preds .B1.2 xor eax, eax ;3.12 ; LOE eax ebx ebp esi edi .B1.5: ; Preds .B1.4 ret ;3.12 ; LOE ; mark_end; @foo@4 ENDP PUBLIC @bar@4 ; --- bar(int) @bar@4 PROC NEAR ; parameter 1: ecx .B2.1: ; Preds .B2.0 L2:: ;7.1 test ecx, 2147483647 ;8.14 push 0 ;8.14 pop eax ;8.14 sete al ;8.14 ret ;8.14 ; LOE ; mark_end; @bar@4 ENDP ;@bar@4 ENDS _TEXT ENDS |
Сообщ.
#50
,
|
|
|
Qraizer, с чем она может быть спараллелена, когда её работа зависит от результата предыдущей операции (всех 3-х предыдущих инструкций, я даже скажу)?
gcc, кстати, срабатывает как xor+test+sete (xor+and+sete для регистра) при оптимизации по скорости для обоих вариантов кода. А вот просто !x или x==0 он компилит аж в: mov edx,[esp+4] xor eax,eax test edx,edx sete al Добавлено Цитата Qraizer @ Жесть какая! push 1 pop eax Тогда бы уж сделали xor eax,eax inc eax Добавлено Цитата Jin X @ Зачем тут xor eax,eax, когда я объявляю тип функции bool? Он же байтовый! xor+test+sete |
Сообщ.
#51
,
|
|
|
Цитата Jin X @ С последующими действиями. Может использоваться либо eax, либо edx, но какой именно, станет известно лишь позднее. Временно можно использовать два потока исполнения, один из которых будет впоследствии отброшен, а второй, использующий "правильный" risc-регистр, переотображён на eax. То же можно сделать с setcc, также задействуя два risc-регистра, однако тут больше сложностей с подготовкой значения для второго. В отличие от cmovcc, где оба значения уже подготовлены и лежат в регистрах, для setcc значения 0 и 1, причём чётко байтовые, нужно подготавливать явно. Вероятно, по этой причине микрокод для них может отличаться. с чем она может быть спараллелена, когда её работа зависит от результата предыдущей операции Добавлено Цитата Jin X @ Соседние push/pop не имеют штрафов по зависимостям. Они спецом для этого оптимизированы. Пара xor/inс зависит от ALU Жесть какая! Добавлено Цитата Jin X @ Ну я же привёл прототипы. Там int. Если хочешь C++, где есть честный bool, то это будут другие прототипы. Зачем тут xor eax,eax, когда я объявляю тип функции bool? Он же байтовый! Добавлено Проверил на intel, никакой разницы. Он всегда предпочитает работать с полноразмерными регистрами, ибо так куда эффективнее работает микрокод. (Вообще, даже самые древние мануалы советуют никогда не смешивать разноразмерные данные в зависимых инструкциях.) А вот visual немного удивил: _TEXT SEGMENT ?bar@@YI_NH@Z PROC ; bar, COMDAT ; _x$ = ecx ; File c:\users\shmatko\documents\intel\документация\qq.cpp ; Line 8 test ecx, 2147483647 ; 7fffffffH sete al ; Line 9 ret 0 ?bar@@YI_NH@Z ENDP ; bar _TEXT ENDS ; Function compile flags: /Ogtpy ; COMDAT ?foo@@YI_NH@Z _TEXT SEGMENT ?foo@@YI_NH@Z PROC ; foo, COMDAT ; _x$ = ecx ; File c:\users\shmatko\documents\intel\документация\qq.cpp ; Line 3 test ecx, ecx je SHORT $LN3@foo cmp ecx, -2147483648 ; 80000000H je SHORT $LN3@foo xor al, al ; Line 4 ret 0 $LN3@foo: ; Line 3 mov al, 1 ; Line 4 ret 0 ?foo@@YI_NH@Z ENDP ; foo _TEXT ENDS Добавлено Тока эта... сегодня VC2017. Добавлено P.S. Цитата Qraizer @ Забыл добавить, что это лишь мои рассуждения, почему такое может иметь место. Как оно на самом деле, без понятия. Временно можно использовать два потока исполнения... |
Сообщ.
#52
,
|
|
|
Цитата Qraizer @ Так, дело не в зависимости, а в использовании стека (то бишь памяти, а это время).Соседние push/pop не имеют штрафов по зависимостям. Цитата Qraizer @ Я заменил int на bool и откомпилил gcc, но результат всё равно почему-то пишется в eax.Ну я же привёл прототипы. Там int. Если хочешь C++, где есть честный bool, то это будут другие прототипы. Цитата Qraizer @ Не спорю (кстати, это может быть причиной использования cmov), просто здесь всё равно используется sete, поэтому xor eax,eax ничего ускорить не должен, по идее...Вообще, даже самые древние мануалы советуют никогда не смешивать разноразмерные данные в зависимых инструкциях Возможно, просто компилер устроен так, что оперирует только полными регистрами. Вот, кстати, надо посмотреть как он будет char возвращать - как байт или дворд. Intel и gcc. |
Сообщ.
#53
,
|
|
|
Цитата Jin X @ Ничего страшного. Ляжет в L1 кэша, ибо вершина стека да в кэш.промахе... когда такое бывало-то, оттуда же прочтётся, а в память запишется в фоне при отбросе кеш.строк, да и то не факт, что не перезапишется к тому времени мульён раз другими данными. Так, дело не в зависимости, а в использовании стека (то бишь памяти, а это время). |
Сообщ.
#54
,
|
|
|
Цитата Qraizer @ Ляжет, но обращение к кэшу тоже требует времени. Кэш (даже L1) - это же не регистры. Ничего страшного. Ляжет в L1 кэша |
Сообщ.
#55
,
|
|
|
Так это не отнимет тактов. Ещё в i486 была очередь отложенных записей, которые не тормозили ALU, в отличие от чтений, а, если не ошибаюсь, в P6 появилась фича вытаскивать эти данные прям из очереди, т.е. даже без обращения к L1. Поспрашивай leo, он больше об этом всём знает.
|
Сообщ.
#56
,
|
|
|
По поводу cmov'ов Агнер пишет так:
Цитата 9.9c - этоThe advantage of a conditional move is that it avoids branch mispredictions. But it has the disadvantage that it increases the length of a dependency chain, while a predicted branch breaks the dependency chain. If the code in example 9.9c is part of a dependency chain then the cmov instruction adds to the length of the chain. The latency of cmov is two clock cycles on Intel processors, and one clock cycle on AMD processors. ; Example 9.9c. Branch implemented with conditional move mov eax, [b] cmp eax, [c] mov eax, [d] cmovng eax, [e] И вот ещё: Цитата Здесь он, конечно, сравнивает setcc с jcc, но всё же не про movcc не пишет, а именно про setcc.If a conditional jump is used for setting a Boolean variable to 0 or 1 then it is often more efficient to use the conditional set instruction. Цитата Qraizer @ Может быть, конечно.в P6 появилась фича вытаскивать эти данные прям из очереди, т.е. даже без обращения к L1 Но я могу лишь судить по таблице скоростей и задержек: http://agner.org/optimize/instruction_tables.pdf Ну и мои тесты показывают, что push 1+pop eax работает медленнее, чем xor eax,eax+inc eax, хотя я понимаю, что при других сочетаниях результаты могут быть другими. Но в любом случае вряд ли push/pop будет когда-либо быстрее, чем xor/inc. Добавлено Собственно, хочется понять: это продуманный умысел Intel (и тогда в чём он?) или недочёт (что было бы странно для производителя процессоров)? Добавлено Цитата Qraizer @ Я его, пожалуй, приглашу в эту тему Поспрашивай leo, он больше об этом всём знает. |
Сообщ.
#57
,
|
|
|
Цитата Jin X @ Думаю, никаких теорий заговоров. У него просто мало информации. Если использовать эти функции в контексте, да ещё и инлайнить, код может отличаться от голых __fastcall функций разительно. Собственно, хочется понять: это продуманный умысел Intel (и тогда в чём он?) или недочёт (что было бы странно для производителя процессоров)? |
Сообщ.
#58
,
|
|
|
Цитата Jin X @ На AMD, судя по таймингам, одинаково, только комбинация push+pop немного длиннее. на intel push+pop выполняется дольше.Ну и мои тесты показывают, что push 1+pop eax работает медленнее, чем xor eax,eax+inc eax, хотя я понимаю, что при других сочетаниях результаты могут быть другими. Но в любом случае вряд ли push/pop будет когда-либо быстрее, чем xor/inc. А непосредственная засылка единицы в регистр на обоих процессорах будет работать ещё быстрее. |
Сообщ.
#59
,
|
|
|
Я вполне допускаю, что засылка значения быстрее и всё такое, но всё же идеологически вижу это медленнее/неправильнее по таким причинам: засылка значения - это как привоз некими 32-мя фурами издалека значения 0 или 1 (распараллелили), а XOR - это работат тут, на месте, недалёкая=простая в геометрико-транзисторном виде, тоже параллельная 32 раза, - должна быть существенно быстрее! Будет ещё, конечно, INC, но и он ничего извне не просит, а может и тут, на месте, молотить. Так что...
Добавлено Цитата Jin X @ Это они практически такие же, но идеологически test не меняет регистр, а лишь "проверяет" (and "в уме") биты, посему ДОЛЖЕН быть быстрее. При этом test edi,edi можно с тем же успехом заменить на and edi,edi или на or edi,edi. Размер тот же, скорость та же. |
Сообщ.
#60
,
|
|
|
Цитата amk @ посему ДОЛЖЕН быть быстрее. Лично я, чтобы так плотно, на асме не прогал лет 20 точно. Но одно - помню, нет такого понятия "ДОЛЖЕН". Есть документация. |