Що ефективніше inc eax або add eax, 1 stack overflow російською

Почав вивчати асемблер, знаю C / C ++. Тому вирішив відштовхуватися від знань, які вже є, і почав розбирати мною написаний код і дивитися як що влаштовано.







І відразу ж натрапив на нелогічний момент.
Якщо в асемблері є функція посилення ролі аргументу inc eax. то вона повинна відрізнятися від додавання 1 до регістру шляхом add eax, 1.
Я зазвичай припускав, що якщо є окремі такі функції, то вони ефективніше. але якщо дивитися код i ++:

Що краще використовувати: inc або add в такому випадку?

Я думаю, що компілятор сглупил. Ймовірно позначається той факт, що теоретично результат i ++ ще може бути потім використовувати і через це він намагається зберегти результат в r \ eax. Насправді компілятор міг би згенерувати просто

Крім того, тут явно цілих три інструкції замість однієї і це вже точно повільніше (якщо тільки значення i ++ не потрібно потім).

Що ж до явного порівняння add eax, 1 і inc eax, то підозрюю, що різниці в швидкості ніякої, але цифра 1 займає місце, а це означає, що вона займе місце в черзі передвибірки коду і може зіграти негативну роль. А може і не зіграти.

З іншого боку, компілятор дійсно наполегливо використовує add eax, 1:

Дає результат без inc'а

З іншого боку, Java JIT-компілятор використовує іноді inc. сам бачив ..







Ну Ви і питання, звичайно, задаєте! Це ж все настільки залізо-залежні речі!

Загальне правило просте: в плані генерації ассемблерного коду компілятор завжди розумніший (обізнаність), ніж Ви. Якщо він робить так, значить, так буде краще.

Друга думка: Ви відштовхуєтеся на хибному посиланні. Введення нових машинних команд далеко не завжди диктується ефективністю обчислень. Є ж ще така річ, як ефективність програмістів - погодьтеся, inc eax написати набагато простіше, ніж add eax, 1;). А операція вкрай часта.

Тепер з приводу того, чому add швидше, ніж inc. (Все що я зараз напишу не повинно бути правдою - просто мені так здається). Справа в тому, що inc. на відміну від add. не змінює стан прапора перенесення. А деякі інші прапори змінює. Оскільки мені не відомо жодної архітектури, на якій можливо виставляти прапори по одному, а не всі скопом, то я намагаюся стверджувати наступне: inc 'у потрібно спочатку вважати поточний стан прапора перенесення (що породжує хибну залежність з подальшим простоєм конвеєра). А add 'у це не потрібно, оскільки він його перезаписує. Звідси і приріст продуктивності.

P.S. Відмова від відповідальності ще раз: я сам в цьому не дуже добре поки розбираюся (звертайтеся через півроку - судячи з усього, на той час я вже буду експертом в цій області =)). Просто десь щось подібне чув \ читав.

відповідь даний 14 Лютого '11 о 21:57

gcc (GCC) 3.4.5 (mingw-vista special r3)

використовує incl для i ++ j ++

при компіляції з -O3 він взагалі тримає змінні в регістрах. gcc -S -O3

робить (для while) код:

З приводу швидкості виконання. Особисто мені здається, що в циклічному коді розумного розміру для сучасної реалізації архітектури x86 швидкість виконання буде, як це не дивно на перший погляд виглядає, однаковою. Це пов'язано з передвибірки команд і їх перетворенням до командам RISC-подібного ядра процесора.







Схожі статті