Подтвердить что ты не робот

Что могут сделать люди из ограничителя?

Если я получил правильное ключевое слово C99 restrict, то присвоить ему указатель - это обещание, что ссылки, которые он ссылается, не будут изменены за компилятором обратно через сглаживание.

В отличие от того, как я понимаю квалификатор const, как в документации, связанной с компилятором, данный объект не будет изменен за спиной человека, пишущего код. Компилятор может получить подсказку как побочный эффект, но как программиста мне все равно.

Аналогичным образом было бы уместным рассматривать квалификатор restrict в прототипе функции как требование, чтобы пользователь обеспечивал эксклюзивный доступ ( "избегать сглаживания" или, может быть, что-то более сильное) на время вызова? Должен ли он использоваться как "документация"?

Кроме того, есть ли что-то понять в том, что restrict квалифицирует указатель, а не данные, на которые он указывает (как это делает const)?

EDIT: Я изначально считал, что restrict может иметь последствия с потоковым кодом, но это кажется неправильным, поэтому я удаляю ссылки на темы из вопроса, чтобы избежать путаницы с читателями.

4b9b3361

Ответ 1

Лучшая "интуиция", связанная с ключевым словом ограничения, заключается в том, что ее гарантия (от программиста к компилятору), которая за время жизни указателя получает доступ к памяти, доступной через этот указатель, ТОЛЬКО через этот указатель, а не с помощью другого указателя или справочного или глобального адреса. Поэтому важно, чтобы его указатель как свойство как указателя, так и памяти связывали их вместе, пока указатель не выходит за рамки.

Ответ 2

У Криса Додда есть правильное описание ключевого слова. На некоторых платформах это может быть очень важно по соображениям производительности, поскольку он позволяет компилятору знать, что после того, как он загрузил данные через этот указатель в регистр, повторите это не нужно. Без этой гарантии компилятор должен перезагружать данные через указатель каждый раз, когда записывается любой другой возможный указатель сглаживания, что может вызвать серьезную остановку трубопровода, называемую load -hit-магазин.

const и restrict - это разные понятия, и это не значит, что const означает restrict. Все const говорят, что вы не будете писать через этот указатель в рамках этой функции. Указатель const может все еще быть псевдонимом. Например, рассмотрим:

int foo( const int *a, int * b )
{
   *b *= 2;
   return *a + *b; // induces LHS: *a must be read back immediately
                   // after write has cleared the store queue
}

В то время как вы не можете напрямую писать в a в этой функции, для вас было бы совершенно право называть foo like:

int x = 3;
foo( &x, &x );  // returns 12

restrict - это другая гарантия: обещание a != b во всех вызовах foo().

Я написал о ключевом слове restrict и последствиях его производительности, а так и Майк Актон. Хотя мы говорим о конкретном PowerPC в заказе, проблема с загрузкой-загрузкой существует и на x86, но выполнение вне очереди порядка x86 затрудняет выделение в профиле.

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

Ответ 3

Большая часть того, что вы знаете, ошибается!

const не гарантирует, что что-то не изменится за компилятором. Все, что он делает, это остановить вы от написания до этого места. Возможно, что-то еще может быть записано в это место, поэтому компилятор НЕ может считать его постоянным.

Как говорили другие, спецификатор ограничения относится к сглаживанию. Фактически, во время первого раунда стандартизации C было предложено слово "noalias". К сожалению, предложение было довольно плохо написано - это вызвало тот факт, что Деннис Ритчи был вовлечен в этот процесс, когда он написал письмо, в котором говорилось что-то о том, что "noalias должен уйти. Это не открыто для переговоров."

Излишне говорить, что "noalias" не стал частью C. Когда пришло время повторить попытку, предложение было написано достаточно хорошо, что ограничение было включено в стандарт - и хотя noalias, вероятно, был бы более значимое имя для него, это имя было настолько испорченным, что я сомневаюсь, что кто-нибудь даже попытался его использовать.

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

void f(int *a, int *b, int *c) { 
    for (int i=0; i<*a; i++)
        *b += c[i];
}

Компилятор действительно хочет поместить я в регистр и загрузить * a в регистр, поэтому, когда приходит время решить, нужно ли выполнять другую итерацию цикла, он просто сравнивает значения в тех, которые регистрируются друг с другом, К сожалению, он не может этого сделать - если кто-то, кто использовал эту функцию, был абсолютно сумасшедшим и назвал его с помощью == b, каждый раз, когда он пишет в * b внутри цикла, это новое значение также является значением * a - поэтому он должен читать * a из памяти на каждой итерации цикла, на всякий случай тот, кто его назвал, был совершенно безумным. Использование ограничения говорит компилятору, что он может генерировать код, предполагая, что a и b всегда будут отличаться, поэтому запись в * a никогда не изменится * b (или наоборот).

Ответ 4

Ваше понимание в основном правильное. Квалификатор restrict просто указывает, что доступ к данным, доступным с помощью такого квалифицированного указателя, доступен только с помощью этого точного указателя. Это относится к чтению в виде колонок, как пишет.

Компилятор не заботится о параллельных потоках, он не собирается генерировать код по-другому, и вы можете собирать свои собственные данные по своему усмотрению. Но ему нужно знать, какие операции указателя могут изменить глобальную память.

restrict также несет с собой API-предупреждение для людей о том, что данная функция реализована с предположением о неустановленных параметрах.

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

Наконец, обратите внимание, что компилятор, вероятно, уже будет анализировать возможное наложение на основе типов данных на более высоких уровнях оптимизации, поэтому restrict важен в основном для функций с несколькими указателями на один и тот же тип данных. Вы можете извлечь урок из этой темы и убедиться, что любое преднамеренное псевдонижение выполняется с помощью union.

Мы можем видеть restrict в действии:

void move(int *a, int *b) {     void move(int *__restrict a, int *__restrict b) {
    a[0] = b[0];                    a[0] = b[0];
    a[1] = b[0];                    a[1] = b[0];
}                               }
    movl    (%edx), %eax            movl    (%edx), %edx
    movl    %eax, (%ecx)            movl    %edx, (%eax)
    movl    (%edx), %eax            movl    %edx, 4(%eax)
    movl    %eax, 4(%ecx)

В правом столбце с restrict компилятору не нужно перечитывать b[0] из памяти. Он смог прочитать b[0] и сохранить его в регистре %edx, а затем просто сохранить регистр дважды в память. В левом столбце он не знал, изменилось ли хранилище на a b.

Ответ 5

Кто-то, более знакомый со стандартом, мог бы дать лучший ответ, но я дам ему шанс.

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

"const" означает, что данные не будут изменены перед программистом; то есть она не может изменять данные через обозначение, обозначенное как "const" (я пишу "signifier", потому что в int const *pi имя pi не const, а *pi is). Данные могут быть модифицируемы с помощью другого знака (в конце концов, неконстантные данные могут быть переданы функции как const-данные).

То, что "ограничивает" квалификационные указатели, является ключом. Указатели - единственный способ для псевдонимов данных на C, поэтому они - единственный способ получить доступ к некоторым частям данных через два разных имени. "Ограничение" - это ограничение ограничения доступа к одному пути доступа.

Ответ 6

Это может быть пример из чрезвычайно узкого домена, но платформа Altera Nios II - это микроконтроллер с мягким сердечником, который вы можете настроить в FPGA. Затем, в исходном коде C для этого микрона, вы можете использовать инструмент C-to-hardware для ускорения внутренних циклов с использованием настраиваемого оборудования, а не программного обеспечения.

В этом случае использование ключевого слова __restrict__ (то же, что и C99 restrict) позволяет инструменту C2H правильно оптимизировать аппаратное ускорение операции указателя параллельно, а не последовательно. По крайней мере, в этом случае restrict просто не предназначен для потребления человеком. См. Также Страница Sun на restrict, где в первой строке указано

Использование квалификатора restrict, соответствующего соответствующим программам C, может позволить компилятору производить значительно более быстрые исполняемые файлы.

Если кому-то интересно читать больше на C2H, этот PDF обсуждает оптимизацию результатов C2H. Раздел __restrict__ приведен на стр. 20.