[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[avr-gcc-list] How to control the optimizer from the C source?
From: |
Bernard Fouché |
Subject: |
[avr-gcc-list] How to control the optimizer from the C source? |
Date: |
Fri, 13 Aug 2004 10:50:52 +0200 |
I met an optimization problem: while porting code from icc to gcc, I had the
following routine:
void set_clkdiv(int mode)
{
CLI();
switch(mode)
{
case 0:
case 1:
CLKPR=0x80;
CLKPR=0x00;
break;
case 2:
CLKPR=0x80;
CLKPR=0x01;
break;
case 4:
CLKPR=0x80;
CLKPR=0x02;
break;
case 8:
CLKPR=0x80;
CLKPR=0x03;
break;
case 16:
CLKPR=0x80;
CLKPR=0x04;
break;
case 32:
CLKPR=0x80;
CLKPR=0x05;
break;
case 64:
CLKPR=0x80;
CLKPR=0x06;
break;
case 128:
CLKPR=0x80;
CLKPR=0x07;
break;
case 256:
CLKPR=0x80;
CLKPR=0x08;
break;
}
SEI(); //re-enable interrupts
}
When compiled with optimization -Os, it produces code like:
[snip]
2358: 81 e0 ldi r24, 0x01 ; 1
235a: 22 c0 rjmp .+68 ; 0x23a0
235c: 80 e8 ldi r24, 0x80 ; 128
235e: 80 93 61 00 sts 0x0061, r24
2362: 82 e0 ldi r24, 0x02 ; 2
2364: 1d c0 rjmp .+58 ; 0x23a0
2366: 80 e8 ldi r24, 0x80 ; 128
2368: 80 93 61 00 sts 0x0061, r24
236c: 83 e0 ldi r24, 0x03 ; 3
236e: 18 c0 rjmp .+48 ; 0x23a0
2370: 80 e8 ldi r24, 0x80 ; 128
2372: 80 93 61 00 sts 0x0061, r24
2376: 84 e0 ldi r24, 0x04 ; 4
2378: 13 c0 rjmp .+38 ; 0x23a0
237a: 80 e8 ldi r24, 0x80 ; 128
237c: 80 93 61 00 sts 0x0061, r24
2380: 85 e0 ldi r24, 0x05 ; 5
2382: 0e c0 rjmp .+28 ; 0x23a0
2384: 80 e8 ldi r24, 0x80 ; 128
2386: 80 93 61 00 sts 0x0061, r24
238a: 86 e0 ldi r24, 0x06 ; 6
238c: 09 c0 rjmp .+18 ; 0x23a0
238e: 80 e8 ldi r24, 0x80 ; 128
2390: 80 93 61 00 sts 0x0061, r24
2394: 87 e0 ldi r24, 0x07 ; 7
2396: 04 c0 rjmp .+8 ; 0x23a0
2398: 80 e8 ldi r24, 0x80 ; 128
239a: 80 93 61 00 sts 0x0061, r24
239e: 88 e0 ldi r24, 0x08 ; 8
23a0: 80 93 61 00 sts 0x0061, r24
23a4: 78 94 sei
23a6: 08 95 ret
the fun thing is that the optimizer does not spare many 'ldi r24,0x80' but
change the code to have at the end of the function 'sts 0x0061,r24' once: it
delayed the second setting of 0x0061 to the end of the function. The problem
is that the clock prescaler register must be touched twice within 4 clock
ticks. If we look at line 237a (for instance), There is:
237a: 80 e8 ldi r24, 0x80 ; 128
237c: 80 93 61 00 sts 0x0061, r24
2380: 85 e0 ldi r24, 0x05 ; 5
2382: 0e c0 rjmp .+28 ; 0x23a0
and then line 23a0:
23a0: 80 93 61 00 sts 0x0061, r24
So timing is critical after line 237c. If I understand correctly atmel docs
(using an ATMEGA162):
2380: 1 cycle
2382: 2 cycles
23a0: 2 cycles
Total: 5
These results would change according to the optimizer settings. It appears
that the only clean solution is to write the code in asm (otherwise the
final software will work or not according to -O values) or to be able to
tell the compiler what to do in such a situation. I don't want to rely on
Makefile since having -O setting for such and such C file and not for
another one seems to be messy. Also the optimizer internals may change in
the future.
So the question is: will gcc have, for instance, some "#pragma" to allow the
definition of time critical sections like the one above or should I use asm
?
Thanks
Bernard
- [avr-gcc-list] How to control the optimizer from the C source?,
Bernard Fouché <=