Имеет ли смысл когда-либо компилятору передавать такую ​​структуру в регистре процессора в функцию? - PullRequest
8 голосов
/ 18 ноября 2010

Я хотел бы знать, если какая-то структура содержит более одного примитива, но его общий размер меньше или равен размеру одного регистра процессора, например, 4-байтового регистра, имеет ли это смысл для компилятора? помещать его в один из этих 4-байтовых регистров при передаче его по значению или ссылке на функцию вместо создания его копии в стеке вызываемого абонента или передачи указателя на него и, в общем, при передаче чего-то большего, чем один примитив пригодится ли функция, подобная массиву или структуре, передающая в регистр процессора?

образец такой структуры:

struct sample{
 public:
  char char1;
  char char2;
};

пример передачи структуры в функцию:

void someFunc(const sample input){
 //whatever
}
void someFunc(sample input){
 //whatever
}
void someFunc(sample & input){
 //whatever
}
void someFunc(const sample & input){
 //whatever
}

Ответы [ 4 ]

5 голосов
/ 18 ноября 2010

Это определено в двоичном интерфейсе приложения (ABI) вашей среды выполнения. Стандарт ничего не говорит о регистрах процессора при вызове функции, поэтому законно создавать среду, в которой небольшие структуры упаковываются в один регистр процессора.

Что касается ссылочной части, то, скорее всего, они все равно будут передаваться как указатели, поскольку, когда внутри вызываемой функции берется адрес ссылки, она должна разрешаться по адресу ссылочного объекта.

4 голосов
/ 18 ноября 2010

Да. Многие компиляторы имеют специальное ключевое слово или атрибут типа, который можно использовать для указания того, что структура должна передаваться в регистрах, а не в стеке. Это чаще встречается на процессорах, которые имеют много регистров и глубоких конвейеров, таких как PowerPC, и может стать огромным улучшением производительности в архитектурах, где запись значения в память и последующее повторное чтение сразу же вызывают остановку конвейера.

Обычно вы используете его только для структуры, которая имеет тот же размер, что и собственный регистр. В частности, это полезно на процессорах, которые имеют широкие регистры SIMD, которые могут пропускать 16 байтов за раз или более. Это позволит вам передать (например) 4-мерный вектор (четыре числа с плавающей запятой) на один регистр. Система AMD V является примером x86 ABI, который разрешает это.

Другим примером является атрибут GCC типа d64_abi, который сообщает PowerPC о необходимости передавать структуру в регистрах, а не в стеке. (Это часть Darwin ABI ).

typedef struct {
    int          a;
    float        f;
    char         c;
} __attribute__ ((d64_abi)) Thingy;

Thingy foo( Thingy t );

В случае выше, вызов Foo передал бы Thingy в один регистр с плавающей запятой и два регистра int, а не записывал его в стек и снова считывал его обратно. Возвращаемое значение возвращается в регистры таким же образом.

Я никогда не видел компилятор, который делает это автоматически, без вашего ведома, но, возможно, он существует.

3 голосов
/ 18 ноября 2010

На некоторых архитектурах (например, i386, я знаю, что он древний, но это то, с чем я вырос;), безусловно, имеет смысл передавать его в регистр, поскольку загрузка и извлечение из стека занимают намного больше времени (скажем, между -6 раз больше) ЦП работает как регистр. Таким образом, компилятор хорошо поработал бы для этого.

Я могу представить, что есть другие архитектуры, где это не имеет значения. Или, если регистры используются для других оптимизаций, которые дают больше улучшений, не имеет смысла использовать их для этого.

Какую архитектуру вы используете / нацеливаете или вообще спрашиваете?

1 голос
/ 18 ноября 2010

Я думаю, что есть компиляторы, которые передают POD в регистры, даже если они struct с.

...