Não consigo entender por que o compilador GCC cortou parte do meu código enquanto preserva absolutamente o mesmo na vizinhança?
O código 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;
}
A parte correspondente do LSS (arquivo do assembler, criado pelo compilador):
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
Eu poderia assumir que o compilador descobre que esse código é falso e o corta, mas por que ele preserva o mesmo no final do código?
Existem instruções do compilador para impedir essa otimização?
Respostas:
Como em um comentário você declara que "cada marca de CPU vale a pena", sugiro o uso de um assembly em linha para fazer com que seus atrasos se repetam da maneira que desejar. Esta solução é superior às várias
volatile
ou-O0
porque deixa claro qual é a sua intenção.Isso deve fazer o truque. A coisa volátil está aí para dizer ao compilador "Eu sei que isso não faz nada, apenas mantenha-o e confie em mim". As três "declarações" asm são bastante autoexplicativas, você pode usar qualquer registro em vez de r24, acredito que o compilador gosta de registros mais baixos, então você pode querer usar um registro alto. Após o primeiro,
:
você deve listar as variáveis de saída (leitura e gravação) c, e não há nenhuma; após o segundo,:
você deve listar as variáveis de entrada (ronly) c; novamente, não há, e o terceiro parâmetro é uma lista separada por vírgula de registradores modificados , neste caso r24. Não tenho certeza se você deve incluir também o registro de status, pois oZERO
sinalizador muda de curso. Eu não o incluí.editar resposta editada conforme solicitado pelo OP. Algumas notas.
O
"+rm"
antes(i)
significa que você está deixando o compilador decidir colocar i em m Emory ou em uma r egister. Isso é bom na maioria dos casos, pois o compilador pode otimizar melhor se for gratuito. No seu caso, acredito que você deseja manter apenas a restrição r para forçar i a ser um registro.fonte
c
variável em vez de literal que10
eu mencionei na resposta original? Estou tentando ler os manuais do GCC sobre o uso adequado da construção de asm, mas está um pouco obscuro para mim agora. Eu ficaria muito grato!Você pode tentar fazer o loop realmente fazer alguma coisa. No momento, o compilador está dizendo com razão "Este loop não está fazendo nada - eu me livrarei dele".
Então você pode tentar uma construção que eu uso com frequência:
Nota: nem todos os destinos do compilador gcc usam a mesma sintaxe de montagem embutida - pode ser necessário ajustá-lo para o seu destino.
fonte
Sim, você poderia assumir isso. Se você declarar a variável i como volátil, instrua o compilador a não otimizar em i.
fonte
register unsigned char volatile i __asm__("r1");
talvez?i
como volátil resolve tudo. Isso é garantido pelo padrão C 5.1.2.3. Um compilador em conformidade não deve otimizar esses loops sei
for volátil. Felizmente, o GCC é um compilador em conformidade. Infelizmente, existem muitos possíveis compiladores C que não estão em conformidade com o padrão, mas isso é irrelevante para esta questão em particular. Não há absolutamente nenhuma necessidade de montador em linha.Após o primeiro loop
i
é uma constante. A inicializaçãoi
e o loop não produzem senão um valor constante. Nada no padrão especifica que esse loop deve ser compilado como está. O padrão também não diz nada sobre o tempo. O código compilado deve se comportar como se o loop estivesse presente e funciona. Você não pode dizer com segurança que essa otimização foi executada sob o padrão (o tempo não conta).O segundo loop também deve ser excluído. Considero que é um bug (ou uma otimização ausente) que não é. Após o loop
i
é zero constante. O código deve ser substituído pela configuraçãoi
como zero.Acho que o GCC se mantém
i
puramente pelo motivo de você executar um acesso à porta (opaco) que pode afetari
.Usar
induzir o GCC a acreditar que o loop faz alguma coisa.
fonte