Трудно ответить на этот вопрос соответственно для произвольного компилятора. То, что могло быть сделано с этим кодом, зависит не только от компилятора, но также и от целевой архитектуры. Я попытаюсь объяснить, что производственный компилятор с хорошими возможностями мог сделать к этому коду.
С точки зрения времени обработки имело бы смысл только вычислять продукт variable1 и variable2 однажды, поскольку они не изменяются в петле.
Вы правы. И поскольку г-н Кэт указал, это называют общее устранение подвыражения. Таким образом компилятор может произвести код, вычисляет выражение только однажды (или даже вычисляет его во время компиляции, если ценности для двух операндов, как известно, постоянные за один раз).
Достойный компилятор может также выполнить устранение подвыражения на функциях, если это может решить, что у функций нет побочных эффектов. GCC, например, может проанализировать функцию, если ее тело доступно, но есть, также чистый
и константа
признаки, которые могут использоваться, чтобы определенно отметить функции, которые должны подвергнуться этой оптимизации (см. Признаки функции).
Учитывая, что нет никакого побочного эффекта, и компилятор в состоянии определить его (в вашем примере, нет ничего стоящего способом), два из отрывков эквивалентны в этом отношении (я сверился с лязгом:-)).
Это требует дополнительной памяти, однако, и я не уверен, как сильно оптимизатор включает это наверху в.
На самом деле это не требует никакой дополнительной памяти. В умножении выполняют регистры процессора и результат сохранен в регистре также. Это - вопрос устранения большого количества кода и использования единственного регистра, чтобы сохранить результат, который является всегда большим (и несомненно делает жизнь легче когда дело доходит до распределение регистра, особенно в петле). Таким образом, если эта оптимизация может быть сделана тогда, она будет сделана без дополнительной платы.
Первое выражение является самым легким прочитать..
И GCC и Лязг выполнят эту оптимизацию. Я не уверен в других компиляторах, тем не менее, таким образом, необходимо будет проверить на себя. Но трудно вообразить любой хороший компилятор, который не делает устранения подвыражения.
Какое-либо из этого изменяется, если я объявляю свои переменные как константы?
Это может. Это называют константным выражением — выражение, которое содержит только константы. Константное выражение может быть оценено во время компиляции, а не во время выполнения. Так, например, если вы, которых предварительно вычислят многократный A, B и C, где и A и B - константы, компилятор <кодируете> A*B выражение только многократный C против той предварительно вычисленной стоимости. Компиляторы могут также сделать это даже с непостоянными величинами, если они могут определить его стоимость во время компиляции и быть уверены, что это не изменяется. Например:
$ cat test.c
inline int foo(int a, int b)
{
return a * b;
}
int main() {
int a;
int b;
a = 1;
b = 2;
return foo(a, b);
}
$ clang -Wall -pedantic -O4 -o test ./test.c
$ otool -tv ./test
./test:
(__TEXT,__text) section
_main:
0000000100000f70 movl $0x00000002,%eax
0000000100000f75 ret
Есть также другая оптимизация, которая может произойти в случае вышеупомянутых отрывков. Ниже некоторые из них, которые приходят на ум:
Первым самое очевидное является развертывание цикла. Так как количество повторений известно во времени выполнения, компилятор может решить разверните петлю. Применяется ли эта оптимизация или не зависит от архитектуры (т.е. некоторые центральные процессоры могут "соединить вашу петлю" и выполнить код быстрее, чем его развернутая версия, которая также делает код большим количеством тайника дружественный при помощи меньшего количества пространства, избегая дополнительных µOP стадий сплава, и т.д.).
Вторая оптимизация, которая может буквально ускорить вещи как 50 раз, использует SIMD инструкция (SSE, AVX и т.д.). Например, GCC очень хорош в нем (Intel должен быть также, если не лучше). Я проверил что следующая функция:
uint8_t dumb_checksum(const uint8_t *p, size_t size)
{
uint8_t s = 0;
size_t i;
for (i = 0; i < size; ++i)
s = (uint8_t)(s + p[i]);
return s;
}
... is transformed into a loop where each step sums 16 values at once (i.e. as in _mm_add_epi8
) with an additional code handling alignment and odd (<16) iterations count. Clang, however, have totally failed at this last time I checked. So GCC may reduce your loop that way, too, even if number of iterations are not known.
И если я могу я хотеть предложить, чтобы вы не оптимизировали свой код, если вы не находите, что он узкое место. Иначе можно потратить впустую адскую партию времени, делая ложную и преждевременную оптимизацию.
Я надеюсь, что это отвечает на ваши вопросы.Good Luck!