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

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

Re: [avr-gcc-list] Re: How to use inversion in if() - might be a bug rep


From: David Brown
Subject: Re: [avr-gcc-list] Re: How to use inversion in if() - might be a bug report ?
Date: Tue, 01 Sep 2009 17:07:52 +0200
User-agent: Thunderbird 2.0.0.22 (Windows/20090605)

Vaclav Peroutka wrote:
> David,
>

(Try to remember to post back to the list, rather than individual users, unless it is specifically an off-list email.)

>> The "bug" is in your code (alternatively, it is in the C standards!).
>> This is the way C works - before any arithmetic or logical operation,
>> and on various other occasions (such as in a if(), while() or switch()
>> test), any data unit smaller than an int gets promoted to an int.  That
> OK, I did not know that it is in C standard.
>

Now you know!

For the future, it's polite to word your posts with the assumption that /you/ have got it wrong, rather than implying the compiler (or library, or other tools) are at fault. The tools do have a few bugs, but user error is more common.

>> means the "~" complement is done as a 16-bit int.  avrgcc is pretty
>> good (not perfect, but not bad) at removing unnecessary 16-bit code
>> when it doesn't affect the results of the operation.  In this case,
>> however, the 16-bit promotion /does/ affect the working of the code,
>> and it must be kept there.
>  From this point of view, if I have "if (++someUCharVariable) {}", the
> result should be always true ? 0xff will be promoted to 0x00ff,
> increased to 0x0100. But this will not happen in avr-gcc (at least in my
> version). The ASM looks like this:
>     if (++someUCharVariable) {
>  e2:    80 91 60 00     lds    r24, 0x0060
>  e6:    8f 5f               subi    r24, 0xFF    ; 255
>  e8:    80 93 60 00     sts    0x0060, r24
>  ec:        80 91 60 00     lds    r24, 0x0060
>  f0:        88 23           and    r24, r24
>  f2:        91 f2           breq    .-92         ; 0x98 <main+0x18>
> which is correct from 8-bit view, but not from ANSI/ISO standard ? No
> 16-bit expansion ?
>

No, what happens is that the operation ++someUCharVariable is carried out as 8-bit. Then the result (0x00, after the overflow) is promoted to 16-bit and tested. The compiler avoids generating the 16-bit instructions here, since the results are the same.

>> Without knowing the compiler flags you used, it's difficult to tell.
>> However, in general later avr-gcc versions often generate larger code
>> because they do more aggressive inlining.  There are compiler flags
>> that counter this behaviour if you want to reduce code size - search
>> in the archives of this mailing list for examples.
> The new flag you probably have on mind is "-fno-inline-small-functions".

Other useful flags include "-fno-split-wide-types" and "--param inline-call-cost=3" (as well as -Os, of course). Results vary by application - sometimes inlining small functions makes code significantly smaller, sometimes significantly bigger.

Using --combine and -fwhole-program can often help too.

> It does not however exist in older GCC 3.4.6. I would propose some
> clever mechanism, which counts number of calls of small functions and
> compares them with length of the function code. Then avr-gcc would make
> a decision if it is better to inline the function or not. But I am not
> compiler programmer. So I don't know if it is even possible.
>

I think that is exactly what the "--param inline-call-cost=3" flag does. However, there are complications that make it difficult for the compiler to get accurate function code lengths and inlining costs at an early enough stage, so there will always be a need for some manual tuning for space-critical code. I expect, however, that at some point the standard configuration for avr-gcc will be changed to have flags set to give a bit smaller code by default.

> Thank you for your explanation,
> Vaclav
>






reply via email to

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