Распределение переменных по регистрам
Регистров общего назначения всего семь, а чаще и того меньше. Регистр EBP используется для организации фреймов (так же называемых стековыми кадрами), регистр EAX по общепринятому соглашению используется для возращения значения функции. Некоторые команды (строковые операции, умножение/деление) работают с фиксированным набором регистров, который на протяжении всей функции приходился держать "под сукном" или постоянно гонять данные от одного регистра к другому, что так же не добавляет производительности.
Стратегия оптимального распределения переменных по регистрам (global registers allocation)— сложная задача, которую еще предстоит решить. Пусть слово "global" не вводит вас в заблуждение. Эта глобальность сугубо локального масштаба, ограниченная одной-единственной функцией, а то и ее частью.
Компиляторы стремятся помещать в регистры наиболее интенсивно используемые переменные, однако, под "интенсивностью" здесь понимается отнюдь не частота использования, а количество "упоминаний". Но ведь не все "упоминания" равнозначны! Вот, например, if (++a % 16) b++; else c++;
обращение к переменной c происходит в 16 раз чаще! Статистка обращений не всегда может быть получена путем прямого анализа исходного кода программы, так что ждать помощи со стороны машины — наивно.
Языки Си/Си++ поддерживают специальное ключевое слово "register", управляющее размещением переменных, однако, оно носит характер рекомендации, а не императива и все три рассматриваемых компилятора его игнорируют, предпочитая интеллекту программиста свой собственный машинный интеллект.
Представляет интерес сравнить распределение переменных по регистрам в глубоко вложенных циклах, поскольку его вклад в общую производительность весьма значителен. Рассмотрим следующий пример:
int *a, *b;
main(int n, char **v)
{
int i,j; int sum=0;
for (i = 0; i < n; i++)
for (j = 0; j < n; j++)
sum += sum*a[n*i + j] + sum/b[j] + x++;
return sum+x;
}