Как предотвратить оптимизацию gcc некоторых операторов в C?

107

Чтобы сделать страницу грязной (включая бит грязи в записи таблицы страниц), я касаюсь первых байтов страницы следующим образом:

pageptr[0] = pageptr[0];

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

volatile int tmp;
tmp = pageptr[0];
pageptr[0] = tmp;

Вроде уловка работает, но несколько некрасиво. Я хотел бы знать, есть ли какие-либо директивы или синтаксис, которые имеют такой же эффект? И я не хочу использовать -O0флаг, так как это также сильно снизит производительность.

ZelluX
источник
8
@Mark -O0 остановит оптимизацию, но также замедлит работу программы. Я просто хочу предотвратить оптимизацию этого фрагмента кода: P
ZelluX
Я хотел бы добавить, что в прошлом даже использование -O0не предотвращало «оптимизацию» мертвого кода, например, когда GCC обнаруживает, что какой-то код не имеет никакого эффекта, он просто удаляет его. AFAIK, это этап даже раньше -O0... Но это только мой опыт
smoothware

Ответы:

91

Отключение оптимизации решает проблему, но в этом нет необходимости. Более безопасная альтернатива - запретить компилятору оптимизировать хранилище с помощью volatileквалификатора типа.

// Assuming pageptr is unsigned char * already...
unsigned char *pageptr = ...;
((unsigned char volatile *)pageptr)[0] = pageptr[0];

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

Таким образом, окружающий код все еще может быть оптимизирован, и ваш код переносится на другие компиляторы, которые не понимают GCC #pragmaили __attribute__синтаксис.

Дитрих Эпп
источник
2
Я бы сказал, что это предпочтительнее отключения оптимизации. Вы по-прежнему можете воспользоваться другими оптимизациями, используя этот метод.
Ben S
3
Решение Дитриха Эппа не работает под компилятором ARM4.1 . Даже решение ZelluX не работает. Альтернативный способ , чтобы сделать эту работу для ARM4.1 находится в растворе ZelluX, делают « Темп » в глобальной изменчивой переменной .
Oculus Dexter
1
Это очень плохо для указанного компилятора.
Алексей Фрунзе
1
@Shocker: GCC все еще может оптимизировать переменную без оптимизации фактического доступа к памяти. Это разные вопросы.
Дитрих Эпп,
2
@jww: это использование соответствует тому, что описано в этом сообщении в блоге. volatileозначает, что доступ к памяти должен происходить так, как написано, а это именно то, что мы хотим. Другими словами, мы тщательно об этом думали, и это означает то, что мы думаем.
Дитрих Эпп
184

Ты можешь использовать

#pragma GCC push_options
#pragma GCC optimize ("O0")

your code

#pragma GCC pop_options

чтобы отключить оптимизацию, начиная с GCC 4.4.

См. Документацию GCC, если вам нужны дополнительные сведения.

Плуг
источник
3
Однако стоит отметить, что это работает только для целых функций, а не для определенных статусов : gcc.gnu.org/onlinedocs/gcc-4.8.2/gcc/… "Каждая функция, которая определяется после этой точки, как если бы атрибут (( optimize ("STRING"))) был указан для этой функции. ".
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
134

Вместо использования новых прагм вы также можете использовать __attribute__((optimize("O0")))для своих нужд. Это имеет то преимущество, что оно применяется только к одной функции, а не ко всем функциям, определенным в одном файле.

Пример использования:

void __attribute__((optimize("O0"))) foo(unsigned char data) {
    // unmodifiable compiler code
}
FRob
источник
3
Что делать, если я не использую -Olevelопцию, но использовал индивидуальные опции, которые она включает отдельно? (В моем случае я не могу определить, какой из вариантов оптимизации нарушает код) .
user2284570