Отказ от ответственности: я не знаю MIPS, но я знаю немного x86, и я думаю, что принцип должен быть таким же ..
В обычном соглашении о вызове функции компилятор помещает значение n
в стек, чтобы передать его функции foo
. Однако существует соглашение fastcall
, которое вы можете использовать, чтобы указать gcc вместо этого передавать значение через регистры. (MSVC также имеет эту опцию, но я не уверен, каков ее синтаксис.)
test.cpp:
int foo1 (int n) { return ++n; }
int foo2 (int n) __attribute__((fastcall));
int foo2 (int n) {
return ++n;
}
Компиляция выше с g++ -O3 -fomit-frame-pointer -c test.cpp
, я получаю для foo1
:
mov eax,DWORD PTR [esp+0x4]
add eax,0x1
ret
Как видите, он считывает значение из стека.
А вот и foo2
:
lea eax,[ecx+0x1]
ret
Теперь оно берет значение непосредственно из регистра.
Конечно, если вы встроите функцию, компилятор сделает простое добавление в тело вашей более крупной функции, независимо от того, какое соглашение о вызовах вы укажете. Но когда вы не можете вставить это в строку, это произойдет.
Отказ от ответственности 2: Я не говорю, что вы должны постоянно угадывать компилятор. Это, вероятно, не практично и необходимо в большинстве случаев. Но не думайте, что он создает идеальный код.
Редактировать 1: Если вы говорите о простых локальных переменных (а не аргументах функций), то да, компилятор будет размещать их в регистрах или в стеке так, как считает нужным.
Редактировать 2: Похоже, что соглашение о вызовах зависит от архитектуры, и MIPS передаст первые четыре аргумента в стеке, как заявил Ричард Пеннингтон в своем ответе. Так что в вашем случае вам не нужно указывать дополнительный атрибут (который на самом деле является специфичным для x86 атрибутом).