Есть ли способ сообщить компилятору C, что у указателя нет хранилищ псевдонимов? - PullRequest
0 голосов
/ 19 сентября 2018

Если компилятор 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, онаhold - единственный, кто пишет в этот элемент массива 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, даже если между двумя операциями чтения есть вызовы функций.

1 Ответ

0 голосов
/ 19 сентября 2018

Во-первых: есть ли способ, которым я могу объявить свои переменные, чтобы дать этот совет компилятору C?

int * restrict p = &arr[17]; утверждает, что только p и выражения указателя основаны на p будет использоваться для доступа к любому объекту, на который указывает p на протяжении блока (кроме объектов, которые не были изменены каким-либо образом).Это позволяет оптимизировать res += *p;, который вы предлагаете.Тот факт, что GCC не так оптимизирует, является проблемой качества в GCC.

Второе: допустима ли моя попытка использовать ограничение здесь?… По сути, мне нужно убедиться, что если я сделаю * p = x в f, то эта запись будет немедленно замечена другими функциями, читающими из arr [17].

Последнее свойство не являетсядействительное использование restrict.Тот факт, что p объявлен restrict и arr[17] изменен с помощью p, означает, что никакой указатель, не основанный на p, не должен использоваться для доступа к arr[17] во время выполнения блока, содержащего p,даже не для чтения.Итак, если что-то в read_array действительно прочитало arr[17] (используя arr, который не основан на p), это было бы нарушением утверждения restrict.

...