почему он использует movl вместо push? - PullRequest
17 голосов
/ 26 декабря 2010

обратите внимание на этот код:

#include <stdio.h>
void a(int a, int b, int c)
{
    char buffer1[5];
    char buffer2[10];
}

int main()
{
    a(1,2,3); 
}

после этого:

gcc -S a.c

эта команда показывает наш исходный код в сборке.

теперь мы можем видеть восновная функция, мы никогда не используем команду «push» для помещения аргументов функции a в стек.и он использовал "movel" вместо этого

main:
 pushl %ebp
 movl %esp, %ebp
 andl $-16, %esp
 subl $16, %esp
 movl $3, 8(%esp)
 movl $2, 4(%esp)
 movl $1, (%esp)
 call a
 leave

, почему это происходит?в чем разница между ними?

Ответы [ 5 ]

17 голосов
/ 27 декабря 2010

Вот что руководство gcc должно сказать об этом:

-mpush-args
-mno-push-args
    Use PUSH operations to store outgoing parameters. This method is shorter and usually
    equally fast as method using SUB/MOV operations and is enabled by default. 
    In some cases disabling it may improve performance because of improved scheduling
    and reduced dependencies.

 -maccumulate-outgoing-args
    If enabled, the maximum amount of space required for outgoing arguments will be
    computed in the function prologue. This is faster on most modern CPUs because of
    reduced dependencies, improved scheduling and reduced stack usage when preferred
    stack boundary is not equal to 2. The drawback is a notable increase in code size.
    This switch implies -mno-push-args. 

Очевидно, -maccumulate-outgoing-args включено по умолчанию, переопределяя -mpush-args.Явная компиляция с -mno-accumulate-outgoing-args возвращается к методу PUSH, здесь.

8 голосов
/ 26 декабря 2010

Этот код просто помещает константы (1, 2, 3) в позиции смещения (обновленного) указателя стека (esp).Компилятор выбирает «толкать» вручную с тем же результатом.

«push» одновременно устанавливает данные и обновляет указатель стека.В этом случае компилятор сводит это только к одному обновлению указателя стека (вместо трех).Интересным экспериментом будет попытка изменить функцию «a», чтобы она принимала только один аргумент, и посмотреть, изменится ли шаблон инструкции.

6 голосов
/ 26 декабря 2010

gcc выполняет все виды оптимизаций, включая выбор инструкций на основе скорости выполнения конкретного оптимизируемого процессора. Вы заметите, что такие вещи, как x *= n, часто заменяются сочетанием SHL, ADD и / или SUB, особенно когда n является константой; в то время как MUL используется только тогда, когда среднее время выполнения (и следы кэша / и т. саб придет дороже).

В случае аргументов функции: MOV может распараллеливаться аппаратно, а PUSH - нет. (Второй PUSH должен ждать окончания первого PUSH из-за обновления регистра esp.) В случае аргументов функции MOV могут выполняться параллельно.

2 голосов
/ 26 декабря 2010

Это на OS X случайно?Я где-то читал, что он требует, чтобы указатель стека был выровнен по 16-байтовым границам.Это могло бы объяснить такой тип генерации кода.

Я нашел статью: http://blogs.embarcadero.com/eboling/2009/05/20/5607

0 голосов
/ 26 декабря 2010

В наборе команд Pentium нет инструкции для помещения константы в стек. Таким образом, использование push будет медленным: программе придется поместить константу в регистр и нажать регистр:

...
movl $1, %eax
pushl %eax
...

Таким образом, компилятор обнаруживает, что использование movl быстрее. Я думаю, вы можете попробовать вызвать вашу функцию с переменной вместо константы:

int x;
scanf("%d", &x); // make sure x is not a constant
a(x, x, x);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...