avr-gcc-list
[Top][All Lists]
Advanced

[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



reply via email to

[Prev in Thread] Current Thread [Next in Thread]