может ли целый массив находиться в каком-то регистре процессора? - PullRequest
3 голосов
/ 08 ноября 2010

Поскольку я не слишком хорошо знаком с регистрами процессора, в целом и в любой архитектуре, особенно x86, и если это касается компилятора с использованием VC ++, мне интересно, возможно ли это для всех элементов массива с крошечным количеством элементов как массив 1-байтовых символов с 4 элементами, которые должны находиться в каком-либо регистре процессора, поскольку я знаю, что это может быть верно для отдельных примитивов, таких как double, integer и т. д.?

когда у нас есть параметр, как показано ниже:

void someFunc(char charArray[4]){
//whatever
}

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

Ответы [ 6 ]

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

Это не зависит от компилятора, и это невозможно.Массивы не могут быть переданы по значению так же, как и другие типы, т.е. они не могут быть скопированы при передаче в функцию.Стандарт C ++ ясен в том, что при обработке сигнатуры функции в объявлении точные эквивалентности следующие:

void foo( char *a );
void foo( char a[] );
void foo( char a[4] );
void foo( char a[ 100000 ] );

Соответствующий компилятор преобразует массив в сигнатуре функции в указатель.Теперь в месте вызова происходит аналогичная операция: если аргумент является массивом, компилятор должен убрать его в указатель на первый элемент.Опять же, размер массива теряется при распаде 1009 *.

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

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

Внутри одной функции массив может храниться в одном или нескольких регистрах, лишь бы компилятор мог генерировать инструкции ЦПУ для манипулирования им, как того требует код. Стандарт на самом деле не определяет, что значит «быть» в регистре. Это частный вопрос между компилятором и отладчиком, и может быть тонкая грань между чем-то, что находится в регистре и полностью «оптимизируется».

В вашем примере параметр является указателем, а не массивом (см. Ответ dribeas). Поэтому было бы необычно, что массив, на который он указывает, мог бы быть регистром. «Основные» архитектуры, с которыми вы, вероятно, имеете дело, не позволяют указатель на регистр, поэтому даже если массив содержался в регистре в вызывающем коде, он должен был бы быть записан в память, чтобы получить указатель на это, чтобы перейти к вызываемому.

Если бы вызов функции был встроенным, то возможна лучшая оптимизация, как если бы вообще не было вызова.

Если вы оберните свой массив в структуру, тогда вы превратите его во что-то, что может быть передано по значению:

struct Foo {
    char a[4];
};

void FooFunc(Foo f) {
    // whatever
}

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

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

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

(В архитектуре x86 вы можете получить доступ к a[0] и a[1], обратившись к al и ah из регистра eax, но это особый случай, который работает, только если индексы известны в время компиляции.)

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

Из пяти или около того компиляторов, с которыми я достаточно знаком (Borland / Turbo C / C ++ от 1.0, Watcom C / C ++ от v8.0, MSC от 5.0, IBM Visual Age C / C ++, gcc различных версии для DOS, Linux и Windows) Я не видел, чтобы эта оптимизация происходила естественным образом.

Была строковая библиотека, имя которой я не помню, которая выполняла оптимизацию, подобную этой в x86 ASM. Возможно, он был частью библиотеки «Самопроизвольная сборка», но никаких гарантий.

0 голосов
/ 08 ноября 2010

Вы спросили, возможно ли это с VC ++ на x86.

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

Вы можете попробовать это и создать некоторый код, в котором у компилятора будет "стимул" поместить его в регистр, но это будет выглядеть довольно странно, как

char x[4];
*((int*)x) = 36587467;

Скомпилируйте это с оптимизацией и ключом / FA и посмотрите на полученный код ассемблера (а затем сообщите нам результаты: -))

Если вы используете его более «естественным» образом, например, для доступа к одиночным символам или инициализации строки, у компилятора нет никаких оснований помещать этот массив в регистр.

Даже при передаче его функции - компилятор может поместить адрес массива в регистр, но не сам массив

0 голосов
/ 08 ноября 2010

В регистре могут храниться только переменные. Вы можете попытаться принудительно сохранить регистр, используя ключевое слово register: register int i;

Массивы по умолчанию являются указателями.

Вы можете получить значение, расположенное в 4-й позиции следующим образом (используя синтаксис указателя):

char c = *(charArray + 4);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...