Ключевое слово restrict - последствия для оптимизации и алиасинга
Я сталкивался с этими двумя разделами в стандарте C11, ссылаясь на restrict
классификатор:
1 #
6.7.3-8
Объект, доступ к которому осуществляется через ограниченный указатель, имеет специальную связь с этим указателем. Эта связь, определенная в 6.7.3.1 ниже, требует, чтобы все обращения к этому объекту использовали, прямо или косвенно, значение этого конкретного указателя.135) Предполагаемое использование ограничителя (например, класса хранения регистров) должно способствовать оптимизации и удаление всех экземпляров классификатора из всех блоков предварительной обработки, составляющих соответствующую программу, не меняет ее значения (т. е. наблюдаемое поведение).
Можете ли вы объяснить мне значение фрагмента скорописи? В моей интерпретации, поскольку это не меняет своего значения, похоже, что использование restrict
просто бессмысленно...
2 #
6.7.3.1-6
Переводчик может свободно игнорировать любые или все возможные последствия использования restrict.
Каковы могут быть эти псевдонимы? Можете ли вы показать мне несколько примеров?
4 ответа
Скоропись в первой цитате в основном гласила:
- Вы можете определить ключевое слово restrict, например, поместив
#define restrict
строка в ваш код, не меняя смысла вашего c-кода. Ваш код может стать немного медленнее из-за пропущенной оптимизации, но во всех случаях вы получите такие же детерминированные результаты, как если бы вы использовали ключевое слово restrict.
Второй абзац означает, что компилятор может игнорировать ключевое слово restrict. Легко как то.
Ограничение не является бессмысленным, оно позволяет компилятору вносить оптимизации, которые в противном случае были бы недопустимы, если возможно наложение указателей. Например, следующая функция:
int foo(int *a, int *b)
{
*a = 5;
*b = 6;
return (*a + *b);
}
Что возвращает эта функция? Если бы ты сказал 11
Ты только отчасти прав. Возвращается 11
если a == b
в этом случае он возвращает 12
или, что еще хуже, частично перекрывается с b, которое может принимать одно из нескольких значений. Чтобы убедиться, что он ведет себя правильно, компилятор должен выдавать код, который
1) stores 5 to a
2) stores 6 to b
3) loads a into a temporary register
4) adds the temp and 6
5) returns the sum
Если вы как программист знаете a == b
Это никогда не произойдет, вы можете сказать компилятору, что не хотите, чтобы он беспокоился об этом, используя ключевое слово restrict.
int foo(int * restrict a, int * restrict b)
Код, который будет сгенерирован для этой функции:
1) store 5 to a
2) store 6 to b
3) return 11
Компилятор смог выполнить оптимизацию, потому что вы обещали, что проблем с алиасами не будет. И, согласно стандарту, если компилятор просто выберет игнорировать ключевое слово restrict, код, который он сгенерирует, будет просто соответствующим (неоптимизированным) кодом в первом случае, который будет работать одинаково для всех экземпляров, которые вас интересуют.
и удаление всех экземпляров классификатора из всех блоков предварительной обработки, составляющих соответствующую программу, не меняет ее значения (то есть наблюдаемого поведения).
Это означает, что в соответствующей программе все restrict
Ключевое слово соблюдайте правила, так что удаление его не изменит результат работы программы.
В частности, в соответствующей программе никакие параметры не передаются как restrict
указатели будут псевдонимами других restrict
указатели. В противном случае удаление ключевого слова может изменить смысл программы.
В обоих параграфах говорится, что "restrict" - просто подсказка для оптимизации, и что реализация может игнорировать ее.