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

2020-12-31 Thread David Brown
Yes, signed types always have such issues.  That is a big reason why I
started by saying you should /never/ be using "char" for arithmetic -
always use int8_t or uint8_t (or int_fast8_t, uint_least8_t, etc., or
application-specific typedefs of these).  Leave "char" for holding
characters - ASCII letters and elements of an ASCII string.

On a chip like the AVR, don't use signed types for arithmetic unless you
actually need negative values, as they are less efficient in some
circumstances.

mvh.,

David


On 31/12/2020 18:18, Jochen Barth wrote:
> Thanks. Did forget to mention that *16/256 instead of >>4 does insert
> some code to add ((2^n) -1) on negative values (because /16 and >>4 is
> not the same).
> 
> So a direct optimization on shr would be better.
> 
> Kind regards, Jochen
> 
> 
> Am 30.12.20 um 12:19 schrieb David Brown:
>> 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  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
>>>



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

2020-12-31 Thread Jochen Barth
Thanks. Did forget to mention that *16/256 instead of >>4 does insert 
some code to add ((2^n) -1) on negative values (because /16 and >>4 is 
not the same).


So a direct optimization on shr would be better.

Kind regards, Jochen


Am 30.12.20 um 12:19 schrieb David Brown:

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  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





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

2020-12-30 Thread David Brown
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  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
>