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

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [avr-gcc-list] Stack usage under heavy inlining


From: Paulo Marques
Subject: Re: [avr-gcc-list] Stack usage under heavy inlining
Date: Mon, 08 Sep 2008 16:18:44 +0100
User-agent: Thunderbird 1.5.0.14 (X11/20071210)


Hi, Eric

Weddington, Eric wrote:
[...]
That's funny. I agree with Linus:
"Gcc inlining is a total and utter pile of shit."
At least it seems that way for the AVR.

GCC has so many compiler switches just for inlining, coupled with
confusing heuristics, it makes it difficult to understand what is
happening with inlining.

Yes, gcc's switches and heuristics can be confusing, but sometimes it can produce some amazing results. Just look at the function I usually use to initialize a serial port:

void init_serial(uint32_t baud_rate)
{
        uint32_t ef_baud1, ef_baud2;
        uint16_t baud_sel1, baud_sel2;
        WORD baud_sel;

        // this code should be all optimized away when compiling with "-combine 
-fwhole-program"
        baud_sel1 = ((uint16_t)(((double)F_CPU/((double)(baud_rate)*16l)-0.5)));
        ef_baud1 = ((uint32_t)(((double)F_CPU/((double)(baud_sel1 + 
1)*16l)+0.5)));
        baud_sel2 = ((uint16_t)(((double)F_CPU/((double)(baud_rate)*8l)-0.5)));
        ef_baud2 = ((uint32_t)(((double)F_CPU/((double)(baud_sel2 + 
1)*8l)+0.5)));
        // low-speed can never be _more_ accurate than high-speed. We select it 
only
        // when it has the _same_ accuracy to improve robustness
        if (ef_baud1 == ef_baud2) {
                UCSR0A = 0;
                baud_sel.w = baud_sel1;
        } else {
                UCSR0A = bit(U2X0);
                baud_sel.w = baud_sel2;
        }

        // enable RxD / TxD and ints
        UCSR0B = bit(RXCIE0) | bit(RXEN0) | bit(TXEN0);
        // set baud rate
        UBRR0H = baud_sel.b.h & 0xF;
        UBRR0L = baud_sel.b.l;
}

Calling it with something like "init_serial(115200)" will "auto-magically" produce something like half a dozen avr instructions that initialize the serial port with the best divider / double speed setting, all calculated at compile time.

If you use "-combine -fwhole-program" the call site might even be on a different source file.

I can try with more recent versions, if someone suspects that this behavior is better in a more recent gcc, but I just wanted to warn other developers who might hit the same problem.

I don't think the behavior has changed in recent versions.

That's what I was afraid, too :(

Interestingly, the lkml post mentions a switch:
-fno-default-inline

I wonder how that would work out for the AVR. Maybe that should be
considered for the AVR default specs, or at least for the WinAVR
Makefile Template and the default AVR Studio Makefile.

I didn't try that one, but interestingly enough, if I compile the project with "-combine -fwhole-program -fno-inline", gcc produces a single version of the init_serial function optimized to the called baud rate _without_ inlining it.

--
Paulo Marques
Software Development Department - Grupo PIE, S.A.
Phone: +351 252 290600, Fax: +351 252 290601
Web: www.grupopie.com

"C++ : increment the value of C and use the old one"




reply via email to

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