Оптимизатор: замените константу const на объект const

Чандлер Каррут в своем беседе о оптимизации компилятора сказал, что компиляторы ужасны при оптимизации функций с параметрами, переданными по ссылке. Я могу понять, что трудно, когда параметр является неконстантной ссылкой, поскольку компилятор должен иметь дело с памятью или когда тип параметра является сложным (какая-то странная структура или класс). Но если параметр является ссылкой на const и встроенным типом, есть ли какие-либо проблемы? Может ли оптимизатор заменить const float& на const float? Это может быть еще более полезно, когда использование инструкций SSE включено, поскольку компилятор сможет правильно выровнять данные для них.

Ответы

Ответ 1

Может ли оптимизатор заменить const float& на const float?

Нет, они не могут этого сделать, потому что это может изменить семантику программы. Ссылка const по-прежнему является ссылкой. Он не может быть заменен значением. Рассмотрим этот пример:

void foo(const float& x, float a[]) {
    cout << x << endl;
    a[0] += 10.5;
    cout << x << endl;
}

int main() {
    float a[1] = { 3.25 };
    foo(a[0], a);
    return 0;
}

Отпечатает

3.25
13.75

Демо 1

Если вы измените const float& на const float, результат будет

3.25
3.25

Демо 2

Проблема заключается в том, что a[0] совпадает с x, но соединение устанавливается вызывающим абонентом, который находится вне контроля оптимизатора.

Ответ 2

Я выслушал, что поговорил на Youtube некоторое время назад.

Оптимизатор не может заменить ссылки, если он не знает, что делает функция на самом деле. Например.

func.c:

 float func(const float& f)
 {
    return f * 2;
 }

main.c:

 float complicated()
 {
     float f = 3.0;
     float f2 = func(f);
     f2 += 42 + f;
     return f2 / 17.0;
 }

 int main()
 {
    std::cout << complicated() << std::endl;
 }

Так что даже tho 'f в сложном не изменяется в func, компилятор не знает этого. Поэтому он должен передать f в качестве ссылки, а func.

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

Если источник недоступен, компилятор должен пройти по ссылке, потому что это контракт функции - аргументы передаются по-разному для одной вещи, но даже если это не так [поскольку dasblinkenlight показывает, что ответ] смысл кода может измениться, если аргумент является ссылкой или нет.

Ответ 3

Еще одна причина, почему эта подстановка не может быть сделана, состоит в том, что функция может фактически const отбросить константу, а затем мутировать переменную, которая будет отражена в области вызова. Это только UB, если переменная, переданная в const, является константой. То есть:

void f(const int & x) {
  const_cast<int &>(x) = 0;
}

int x = 1;
f(x);

Является законным и делает то, что вы ожидаете. Конечно, этот код отвратительный и т.д., Но все же законный. Измените ссылку const на байпас по значению, и вы измените программу, сделав компилятор несоответствующим. Из-за const_cast и того, как широко он может быть использован, компиляторы действительно не используют const (за исключением, в некоторой степени, локальных переменных); Чандлер упоминает об этом также в одном из своих разговоров.

Ответ 4

Но если параметр является ссылкой на const и встроенным типом действительно ли какие-либо проблемы?

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

Может ли оптимизатор заменить const float & с const float?

@dasblinkenlight является очень хорошим примером того, что оптимизация невозможна, поскольку она влияет на видимое поведение кода, который оптимизаторы не могут изменить. Реальная регрессия состоит в том, что обычно sizeof (float&) > sizeof(float), поэтому вы технически потребляете больше байтов для этого параметра; в то время как true, это фактически не имеет значения, особенно если оно передано в регистр.

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