Рассмотрим такой пример:



По входным данным x и y вычисляются массивы sum, product, update_me, sum_product:

sum[i]=x[i]+y[i];
product[i]=x[i]*y[i];
even[i]=i*2;
sum_product[i]=sum[i]+product[i];

Компилятор генерирует ассемблерный код, суть которого сводится к следующему:

• вычислить следующий sum[i] и поместить в память это значение
• вычислить следующий product[i] и поместить в память это значение
• вычислить следующий even[i] и поместить в память это значение
• вычислить следующий sum_product[i] — на этой стадии придется снова загружать из памяти подсчитанные sum[i] и product[i].

Можно подумать, что четвёртый шаг не оптимальный. В самом деле: подсчитанные sum[i] и product[i] не обязательно снова загружать из памяти, ведь мы их только что подсчитали.
Но оказывается, что никакие ключи оптимизации для данного C-кода не позволят использовать значения, сохранённые в регистрах, полученные на шагах 1 и 2.

Вопрос 1: попробуйте объяснить такое "неоптимальное" поведение компилятора
Вопрос 2: попробуйте предложить решение (если оно есть), которое позволит избежать лишних чтений данных из памяти.

Комментарии
20.06.2015 в 10:21

тролль - это не только ценный жир, но и 3-4 легкоусвояемых коммента ежедневно
компилятор тут не может ничего соптимизировать, а вдруг even == sum ?
20.06.2015 в 11:13

CD_Eater, да, это правильный ответ.
Более того, он для sum и product для раза загружает i и j!

Собственно, это избежать можно, пометив массивы ключевым словом restrict.

получится следующее:

читать дальше

код короче в 3 раза.
20.06.2015 в 11:39

Потому что говоришь загружать из памяти, потому и загружает из памяти.
Задача изначально не особо корректна, ибо
Можно подумать, что четвёртый шаг не оптимальный. В самом деле: подсчитанные sum[i] и product[i] не обязательно снова загружать из памяти, ведь мы их только что подсчитали.
нельзя так подумать, эти действия (взять из памяти и взять из регистров) семантически различны, и то, что оно "только что посчитало" никакого значения не имеет.
Память может меняться за пределами функции (из другого потока, например) или как сказали выше - используемые области могут где-то пересекаться, соответственно компилятор не имеет права взять значение из регистров.

Ну а если сильно хочецца, то можно чуть хитрее.


А самой прямолинейной оптимизацией будут банально временные переменные. Компилятор уловит семантику и эффективнее начнёт использовать регистры.