Если компилятор C знает, что указатель не имеет псевдонима, он может выполнить множество оптимизаций. Например, если я скомпилирую следующую функцию с gcc -O2
:
int f_noalias(int *arr, int x)
{
int res = 0;
int *p = &arr[17];
*p = x;
res += *p;
res += *p;
return res;
}
компилятор знает, что чтение *p
всегда будет оцениваться как x
, поэтому сгенерированный код эквивалентен сгенерированному для следующей функции:
int f_noalias2(int *arr, int x)
{
int *p = &arr[17];
*p = x;
return 2*x;
}
Однако, если компилятор считает, что указатель может иметь псевдоним, он больше не выполняет эту оптимизацию. Например, если мы изменим f
так, чтобы неизвестная функция вызывалась между операциями чтения в *p
, сгенерированный код дважды разыменует p
. Компилятор предполагает, что функция read_arr
могла изменить значение, на которое указывает p
.
int f_withalias(int *arr, int x)
{
int res = 0;
int *p = &arr[17];
*p = x;
res += *p;
read_array(arr);
res += *p;
return res;
}
В моей конкретной программе, когда функция f
работает, указатель p
, который она содержит, является единственным, который записывает в этот элемент массива arr
. Другие функции в коде могут в это время читать из arr
, но не будут записывать в него. (Однако они могут записать другие значения в arr
после завершения работы f
.)
Итак, теперь у меня три вопроса:
Во-первых: Могу ли я объявить свои переменные, чтобы дать эту подсказку компилятору C? Я попытался добавить аннотацию ограничения к p
, но сгенерированный код под gcc -O2
был идентичен сгенерированному коду для f_withalias
int f_restrict(int *arr, int x)
{
int res = 0;
int * restrict p = &arr[17];
*p = x;
res += *p;
read_array(arr);
res += *p;
return res;
}
Во-вторых: Достоверна ли моя попытка использовать здесь ограничение? Как я понимаю, ограничение означает, что никакие другие указатели не могут использовать псевдоним p как для чтения, так и для записи. Но в моем случае функция read_arr
также может получить доступ к массиву arr
, на который указывает p
.
Третье: Если ответ на предыдущий вопрос "нет", могу ли я попробовать что-то другое вместо restrict
?
По сути, мне нужно убедиться, что если я сделаю *p = x
в f
, то эта запись будет немедленно замечена другими функциями, читающими из arr[17]
. Однако я хочу, чтобы GCC мог свободно оптимизировать такие вещи, как x = *p; y = *p
до x = *p; y = x
, даже если между двумя операциями чтения есть вызовы функций.
restrict
кp
иarr
в одном и том же коде? - person chux - Reinstate Monica   schedule 19.09.2018int *arr
наint * restrict arr
не дало результата. - person hugomg   schedule 19.09.2018restrict
может привести к оптимизации, запрещенной в противном случае, отсутствие видимой оптимизации не означает бесполезного использованияrestrict
. Просто это было бесполезно для этой компиляции/вариантов. Удачи. - person chux - Reinstate Monica   schedule 19.09.2018*p
в локальную переменную один раз передread_array
? - person Shafik Yaghmour   schedule 19.09.2018x
, и*p
, я бы хотел, чтобы GCC знал, что если x не может быть сохранен в регистре, то его можно пересчитать из p по мере необходимости. Нет необходимости осторожно пересыпать его в стопку и обратно - person hugomg   schedule 19.09.2018p
, не будет в рамкахf_restrict
, и тем не менее вы получаете к нему доступ.restrict
- это контракт между программистом и компилятором, компилятор не будет проверять такой доступ, а скорее доверяет программисту. Я не верю, что gcc жалуется, если вы выполняете неявное преобразование изtype* restrict
вtype*
, что сомнительно. - person Lundin   schedule 19.09.2018restrict
. - person Lundin   schedule 19.09.2018