Рассмотрим такой пример:
По входным данным 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: попробуйте предложить решение (если оно есть), которое позволит избежать лишних чтений данных из памяти.
По входным данным 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: попробуйте предложить решение (если оно есть), которое позволит избежать лишних чтений данных из памяти.
Более того, он для sum и product для раза загружает i и j!
Собственно, это избежать можно, пометив массивы ключевым словом restrict.
получится следующее:
читать дальше
код короче в 3 раза.
Задача изначально не особо корректна, ибо
Можно подумать, что четвёртый шаг не оптимальный. В самом деле: подсчитанные sum[i] и product[i] не обязательно снова загружать из памяти, ведь мы их только что подсчитали.
нельзя так подумать, эти действия (взять из памяти и взять из регистров) семантически различны, и то, что оно "только что посчитало" никакого значения не имеет.
Память может меняться за пределами функции (из другого потока, например) или как сказали выше - используемые области могут где-то пересекаться, соответственно компилятор не имеет права взять значение из регистров.
Ну а если сильно хочецца, то можно чуть хитрее.
А самой прямолинейной оптимизацией будут банально временные переменные. Компилятор уловит семантику и эффективнее начнёт использовать регистры.