Я не могу понять, почему компилятор GCC вырезал часть моего кода, в то время как он сохранил абсолютно тот же самый по соседству?
Код C:
#define setb_SYNCO do{(PORTA|= (1<<0));} while(0);
ISR(INT0_vect){
unsigned char i;
i = 10;
while(i>0)i--; // first pause - omitted
setb_SYNCO;
setb_GATE;
i=30;
clrb_SYNCO;
while(i>0)i--; // second pause - preserved
clrb_GATE;
}
Соответствующая часть LSS (файл ассемблера, созданный компилятором):
ISR(INT0_vect){
a4: 1f 92 push r1
a6: 0f 92 push r0
a8: 0f b6 in r0, 0x3f ; 63
aa: 0f 92 push r0
ac: 11 24 eor r1, r1
ae: 8f 93 push r24
unsigned char i;
i = 10;
while(i>0)i--;
setb_SYNCO;
b0: d8 9a sbi 0x1b, 0 ; 27
setb_GATE;
b2: d9 9a sbi 0x1b, 1 ; 27
i=30;
clrb_SYNCO;
b4: d8 98 cbi 0x1b, 0 ; 27
b6: 8e e1 ldi r24, 0x1E ; 30
b8: 81 50 subi r24, 0x01 ; 1
while(i>0)i--;
ba: f1 f7 brne .-4 ; 0xb8 <__vector_1+0x14>
clrb_GATE;
bc: d9 98 cbi 0x1b, 1 ; 27
}
be: 8f 91 pop r24
c0: 0f 90 pop r0
c2: 0f be out 0x3f, r0 ; 63
c4: 0f 90 pop r0
c6: 1f 90 pop r1
c8: 18 95 reti
Я мог бы предположить, что компилятор выяснит, что такой код является фиктивным, и вырезает его, но почему он сохраняет тот же самый код в конце кода?
Есть ли какие-либо инструкции компилятора, чтобы предотвратить такую оптимизацию?
Ответы:
Поскольку в одном комментарии вы утверждаете, что «каждый такт процессора достоин», я предлагаю использовать некоторую встроенную сборку, чтобы сделать цикл задержек именно таким, как вы хотите. Это решение превосходит различные
volatile
или-O0
потому, что оно проясняет ваши намерения.Это должно делать свое дело. Изменчивая вещь заключается в том, чтобы сказать компилятору: «Я знаю, что это ничего не делает, просто держи это и поверь мне». Три ассемблерных «утверждения» вполне понятны, вы можете использовать любой регистр вместо r24, я считаю, что компилятору нравятся младшие регистры, поэтому вы можете захотеть использовать старшие. После первого
:
вы должны перечислить выходные (чтение и запись) переменные c, а их нет, после второго:
вы должны перечислить входные (ronly) переменные c, опять же, их нет, а третий параметр - разделенный запятыми список модифицированных регистров. в данном случае р24. Я не уверен, стоит ли вам включать регистр статуса, посколькуZERO
флаг, конечно, меняется, я его не включал.отредактируйте отредактированный ответ как запрос OP Некоторые заметки.
"+rm"
Перед тем(i)
означает , что вы выпускающих компилятор решил место я в м Эмори или в г egister. В большинстве случаев это хорошо, так как компилятор может оптимизировать лучше, если он бесплатный. В вашем случае я считаю, что вы хотите оставить только ограничение r, чтобы заставить i быть регистром.источник
c
переменную вместо литерала, который10
я упоминал в исходном ответе? Я пытаюсь прочитать руководства GCC, касающиеся правильного использования конструкции asm, но сейчас она для меня немного неясна. Я был бы очень признателен!Вы можете попробовать сделать цикл на самом деле сделать что-то. В его нынешнем виде компилятор совершенно правильно говорит: «Этот цикл ничего не делает - я от него избавлюсь».
Таким образом, вы можете попробовать конструкцию, которую я часто использую:
Примечание: не все цели для компилятора gcc используют один и тот же синтаксис встроенной сборки - вам может потребоваться настроить его для своей цели.
источник
Да, вы могли бы предположить это. Если вы объявляете переменную i как volatile, вы говорите компилятору не оптимизировать i.
источник
register unsigned char volatile i __asm__("r1");
может быть?i
как изменчивое решает все. Это гарантируется стандартом C 5.1.2.3. Соответствующий компилятор не должен оптимизировать эти циклы, еслиi
он изменчив. К счастью, GCC - соответствующий компилятор. К сожалению, есть много потенциальных C-компиляторов, которые не соответствуют стандарту, но это не имеет отношения к этому конкретному вопросу. Абсолютно не нужен встроенный ассемблер.После первого цикла
i
это константа. Инициализацияi
и цикл ничего не делают, кроме как выдают постоянное значение. Ничто в стандарте не указывает, что этот цикл должен быть скомпилирован как есть. Стандарт также ничего не говорит о сроках. Скомпилированный код должен вести себя так, как если бы цикл присутствовал, и это так. Вы не можете достоверно сказать, что эта оптимизация была выполнена по стандарту (время не учитывается).Второй цикл также должен быть удален. Я считаю это ошибкой (или отсутствующей оптимизацией), что это не так. После цикла
i
постоянный ноль. Код должен быть заменен установкойi
на ноль.Я думаю, что GCC хранится
i
исключительно по той причине, что выполнение (непрозрачного) доступа к порту может повлиятьi
.использование
чтобы заставить GCC поверить, что цикл что-то делает.
источник