GCC оптимизация чистых функций

Меня смущают гарантии, которые GCC дает в отношении оптимизации pure функции (от онлайн документы):

pure

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

Интересно без чистого функции — это функции с бесконечными циклами или функции, зависящие от энергозависимой памяти или других системных ресурсов, которые могут изменяться между двумя последовательными вызовами (такими как feof в многопоточной среде).

И для const:

const

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

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

Итак, я попытался создать функцию, которая принимает параметр указателя, и попытался пометить его pure, Тем не менее, я попытался скомпилировать эту функцию с помощью GCC онлайн (я пробовал оба const а также pure):

typedef struct
{
int32_t start;
int32_t end;
}
Buffer;

inline __attribute__((pure,always_inline)) int32_t getLen(Buffer * b)
{
return b->end - b->start;
}

И заметил, что GCC (по крайней мере, несколько онлайн версии компилятора Я пробовал):

  1. не оптимизировать вызывает эту функцию (т.е. вызывает ее несколько раз), если Buffer* параметр указывает на глобальное значение,
  2. Оптимизирует вызывает эту функцию (т.е. вызывает ее только один раз), если
    переданный указатель указывает на локальную (стековую) переменную.
  3. оба случая работают одинаково, даже если я отмечаю функцию const вместо pure, но предположительно const игнорируется, если есть аргумент-указатель?

Это хорошая вещь, потому что глобальный Buffer может измениться другим потоком / прерыванием в любое время, в то время как локальный Buffer совершенно безопасен для оптимизации.

Но я полностью смущен замечаниями относительно проходных указателей. Есть ли место, где поведение GCC явно определяется для pure функции, принимающие аргументы указателя?

5

Решение

Есть ли место, где поведение GCC явно определено для чистых функций, принимающих аргументы указателя?

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

Вы сильно запутали вещи, написав свои чистые и константные функции как встроенные; если тело функции доступно компилятору на сайте вызова, он может сам определить, какие операции выполняет вызываемая функция. Атрибуты pure и const наиболее полезны, когда тело функции не видно, так как оно будет определено в отдельном модуле компиляции.

Например, рассмотрим следующую коллекцию не чистых, чистых и константных функций:

__attribute__((__pure__)) int a();
__attribute__((__const__)) int b();
void c();

Если мы позвоним a дважды подряд, без вставки операции, мы можем свернуть это в один вызов, так как a гарантируется доступ к глобальной памяти только для чтения; даже если другой поток пишет в глобальную память примерно в то же время, для a для связи с этим потоком, чтобы компилятор мог предположить, что запись происходит до или после обоих вызовов a:

int f() {
int i = a();
i += a();
return i;  // optimized to "return a() * 2;"}

Если мы позвоним c между звонками a мы должны предположить, что возвращаемое значение a может зависеть от звонка c:

int g() {
int i = a();
c();
i += a();
return i;  // no optimization possible
}

Однако если вместо чистого a мы называем конст bмы можем свернуть это в один вызов, так как b не может прочитать любую память, которая c может написать:

int h() {
int i = b();
c();
i += b();
return i;  // optimized to "c(); return b() * 2;"}
4

Другие решения

«гарантии, которые дает GCC».

Это не так. pure а также const атрибуты обещания тот вы сделать в GCC.

Когда вы делаете эти обещания, оптимизатор может быть быть в состоянии установить сглаживание определенных переменных. Но даже там, где это возможно, этот сглаживание может не иметь отношения к оптимизации (либо потому, что его недостаточно, либо нет). Добавление pure а также const не имеет значения тогда.

1

По вопросам рекламы [email protected]