Почему модификатор __restrict__ не применяется? - PullRequest
1 голос
/ 21 апреля 2020

Если параметр функции аннотирован const int &x, и я пытаюсь сделать x++ в теле функции, я получаю ошибку времени компиляции для изменения ссылки только для чтения. Но если я использую модификатор __restrict__ следующим образом:

void foo(int & __restrict__ a, int & __restrict__ b) {
    if (a == 1)
        b = 2;
    if (a == 2)
        b = 3;
}

int main() {
    int x = 1;
    foo(x, x); // should be illegal?
    cout << x;
}

... Я не получаю ошибку времени компиляции. Если я запускаю этот код неоптимизированно, вывод равен 3, но если я запускаю его с -O1 или выше, вывод равен 2. Кажется, что обнаружение x, которое будет передано дважды, было бы простым и легким для запрета. Почему C ++ защищает от неправильного использования const, а не от неправильного использования __restrict__?

Ответы [ 3 ]

3 голосов
/ 21 апреля 2020

Вы смотрите на __restrict__ в обратном направлении.

__restrict__ - это расширение реализации, которое программист может использовать для сигнализации намерение , чтобы максимизировать сгенерированный код качество и производительность («оптимизация»).

Это не проверка или добавленное ограничение для программы.

Это не часть системы типов, поэтому она не является частью Тип функции, поэтому ее нельзя применять на вызывных площадках (в общем).

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

В этом случае вы говорите: «Я не обращаюсь к pointee через любой другой указатель».

Вы не спрашиваете «пожалуйста, не позволяйте мне обращаться к pointee через любой другой указатель ".

C, и компиляторы C ++ уже выполняют строгие проверки" псевдонимов ", где они могут. Ключевое слово __restrict__ позволяет вам сообщить it «Я уверен в этом», в тех случаях, когда автоматическое обнаружение псевдонимов c не может работать (из-за Например, перевод единицы границ). Поскольку автоматическое обнаружение псевдонимов c не может работать, __restrict__ не может быть применено.

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

3 голосов
/ 21 апреля 2020

В самом общем случае это невозможно диагностировать во время компиляции. В качестве одного простого примера счетчика рассмотрим:

 void foo(int* __restrict__ a, int * __restrict__ b);

 int x;
 int y;
 std::cin >> x >> y;
 int* a = (x%2) ? &x : &y;
 int* b = (y%2) ? &x : &y;
 foo(a,b);

Компилятор не может знать, будут ли a и b указывать на одно и то же int. На самом деле, если бы компилятор мог выполнить такой анализ, в квалификаторе __restrict__ не было бы необходимости, потому что тогда компилятор сам мог бы выяснить, используются ли два указателя для доступа к одной и той же памяти.

2 голосов
/ 21 апреля 2020

Не так просто обнаружить нарушение restrict в целом. Предположим, у вас есть функция

void bar(int* p1, int* p2) {
    foo(*p1, *p2);
}

Что должен делать компилятор в этом случае?

В некоторых случаях (как в вашем примере) нарушение restrict может быть обнаружено и обнаружено некоторые компиляторы. Например, G CC с -Wrestrict выдает предупреждение:

предупреждение: передача аргумента 1 в псевдонимы ограниченного параметра с аргументом 2

G CC Документация в -Wrestrict гласит:

Предупреждать, когда объект ссылается на restrict -качественный параметр (или, в C ++, __restrict -качественный параметр) псевдоним другого аргумента, или когда копии между такими объектами перекрываются.

Вы можете превратить это предупреждение в ошибку, используя опцию -Werror=restrict.

...