?

Log in

No account? Create an account

Previous Entry | Next Entry

Оптимизация в GCC

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

	volatile uint8_t  G_scheduler_reg1 = 0;
	volatile uint8_t  G_scheduler_reg2 = 0;

на

	register uint8_t  G_scheduler_reg1 asm("r3");
	register uint8_t  G_scheduler_reg2 asm("r4");

Компилится нормально, без ошибок и варнингов, экономия кода заметна невооружённым глазом. Только вот ассемблерник смущает — указанные регистры во многих местах используются не так, как я предполагал. Ну да ладно, списываю на компилятор — ему виднее, к тому же в доках написано, что даже если регистр указан явно, компилятор в некоторых случаях может использовать его по своему усмотрению.
В итоге приложение, конечно же, не заработало и долго я вкуривал в код, пока не вспомнил про пресловутый volatile (я допустил ещё одну серьёзную программерскую ошибку — между этой правкой и тестированием внёс в код ещё ряд изменений). Ну не думал я, что gcc и регистры ТАК оптимизирует. Кроме того, ещё одной причиной, по которой я не сразу сообразил в чём беда, было то, что эти переменные у меня используются и на чтение и на запись как в основной функции. так и в прерываниях, так что, вроде, заменять их на константы там негде.
Возвращение в объявление переменных злополучного модификатора volatile сразу программу починило. Но самое смешное в том, что итоговый файл стал меньше ещё на два байта по сравнению с вариантом без volatile =). (используется оптимизация -O2, так что, возможно, компилятор хотел сделать программу быстрее за счёт выбрасывания этих регистров)
Отсюда вывод — все глобальные переменные я теперь объявляю как volatile — может где-то что-то будет хуже соптимизированно, зато не надо будет долго искать аномальные косяки и непонятно откуда вылезшие подводные камни.