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

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

Re: odd optimization differences of shift between C andC++


From: David Brown
Subject: Re: odd optimization differences of shift between C andC++
Date: Wed, 30 Dec 2020 12:19:57 +0100
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Thunderbird/60.4.0

Hi,

As a general point, never use "char" like this - use either uint8_t or
int8_t depending on whether you want signed or unsigned.  Usually if you
are doing shifts, it's uint8_t you want.

The AVR compiler has trouble with some of these kinds of expressions.  I
think it has something to do with the way gcc handles them (most cpus
have instructions for multiple shifts or rotates) combined with the
integer promotion.  The AVR gcc port has 16-bit int (it's the smallest
size allowed by C and C++), which means everything has to be done with
double registers, then there are peepholes and other optimisation passes
that try to remove the redundant code.  A lot of that is manual work
added to the compiler, and so there are bound to be combinations that
have not been included.  Each suboptimal combination has to be spotted,
then added to the compiler.

The different rearrangements done earlier in the compile process can
also mean that the internal code passed to the backend optimiser can
vary substantially.  For example, with most gcc ports, you can split
expressions into multiple local variables without it affecting the
(optimised) results.  For the AVR, that does not always apply.

This all means it is not easy to guess the source code to use to get the
optimal results.  These three versions all give the same code for both C
and C++, with shorter and faster code than 5 shifts (it has one
nibble-swap, one shift and one mask).

uint8_t u;

void fooa(void) {
    u = ((u & 0xe0) >> 5);
}

void foob(void) {
    u = u / (1u << 5);
}

void fooc(void) {
    u = (u >> 5) & 0x07;
}


You can also consider using the "-mint8" flag.  That breaks C
compatibility but it can be useful for small programs, and can often
result in better code.  Be very careful to stick to <stdint.h> types
rather than "int" and "long" if you are trying this!

David



On 29/12/2020 21:00, Jochen Barth wrote:
> I'm using Arduino 1.8.13 with avr-g++ (GCC) 7.3.0.
> 
> char x;
> x >>= 5 generates asm (promoted to 16 bit signed) with 5* asr+ror;
> x = x * (1<<(8-5)) / 256
> generates 5* asr (without type promotion).
> 
> Kind regards,
> Jochen
> 
> 
> Weddington, Eric Mon, 08 Nov 2010 04:25:48 -0800 
>> -----Original Message-----
>> From: 
>> avr-gcc-list-bounces+eric.weddington=atmel....@nongnu.org 
>> [mailto:avr-gcc-list-bounces+eric.weddington=atmel....@nongnu.
>> org] On Behalf Of William "Chops" Westfield
>> Sent: Sunday, November 07, 2010 9:58 PM
>> To: avr-gcc-list@nongnu.org
>> Subject: [avr-gcc-list] odd optimization differences of shift 
>> between C andC++
>> 
>> 
>> 
>> Is this expected? Is it bug-worthy ? 
>> 
> 
> I would say that it's bug-worthy, as a missed optimization bug. FYI, there 
> are 
> more bugs with the C++ compiler for the AVR than for the C compiler. So I'm 
> not 
> totally surprised that this is happening.
> 
> BTW, could you please subscribe to the mailing list? That way your posts do 
> not 
> have to be approved by hand.
> 
> _______________________________________________
> AVR-GCC-list mailing list
> AVR-GCC-list@nongnu.org
> http://lists.nongnu.org/mailman/listinfo/avr-gcc-list
> 




reply via email to

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