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

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

Re: [avr-gcc-list] 8 bit bitwise operation promoted to 16 bit values


From: Theodore A. Roth
Subject: Re: [avr-gcc-list] 8 bit bitwise operation promoted to 16 bit values
Date: Sun, 26 Oct 2003 09:17:17 -0800 (PST)

On Sun, 26 Oct 2003, Neil Johnson wrote:

> Alex,
> 
> > I was surprised a while ago to learn that the compiler can promote 8 bit
> > bitwise operations to 16 bit sometimes, so I had a look through some of
> > my code and looked at the LST files and sure enough there were some.
> 
> Well, its more a case of the compiler must behave as if they are always
> promoted (this is defined in the language standard), but can optimize the
> code where the compiler can determine that such optimization is safe (i.e.
> will produce code that behaves exactly *as if* the expression was computed
> all in ints).
> 
> >   if( RxByte & 0x80 )
> 
> Here the optimizer can determine that 0x80 will fit into an 8-bit unsigned
> char, so the result will be either 0x00 or 0x80 and thus can be optimized
> to 8-bit ops.
> 
> >   if( ( ( LN_TX_PORT >> LN_TX_BIT ) & 0x01 ) == ( ( LN_RX_PORT >>
> > LN_RX_BIT ) & 0x01 ) )
> 
> Why do it this way?  Seems a tad silly to pay the cost of two runtime
> shifts.  Why not do:
> 
>     if ( LN_TX_PORT & ( 0x01 << LN_TX_BIT ) ==
>          LN_RX_PORT & ( 0x01 << LN_RX_BIT ) )
>     {
>         ...
>     }

Won't this always evaluate to false unless (LN_TX_BIT == LN_RX_BIT)?

The only way I can see this working is like this:

     if ( LN_TX_PORT & ( 0x01 << LN_TX_BIT ) &&
          LN_RX_PORT & ( 0x01 << LN_RX_BIT ) )
     {
         ...
     }
                                                                                


> 
> In this code the two shifts should be folded by the compiler into
> constants (this is mandated by the standard), reducing the expression to
> two 8-bit bitwise ANDs and a compare.  The optimizer should be able to
> convert this into 8-bit ops.
> 
> >   if( ( ( LN_TX_PORT >> LN_TX_BIT ) & (byte)0x01 ) == ( ( LN_RX_PORT >>
> > LN_RX_BIT ) & (byte)0x01 ) )
> 
> Unlikely to help, and the shift will still cause a promotion to int.
> 
> >   register byte Mask ;
> >   Mask = 0x01 ;
> >   if( ( ( LN_TX_PORT >> LN_TX_BIT ) & Mask ) == ( ( LN_RX_PORT >>
> > LN_RX_BIT ) & Mask ) )
> 
> A nasty trick to force the optimizer to spot something which can be
> avoided with a bit of careful code (see above).  Even better might be to
> use the bit test macros that are, I believe, in the libs somewhere.
> E.g. use the "bit_is_set" macro, the code becomes:
> 
>     if ( bit_is_set( LN_TX_PORT, LN_TX_BIT ) ==
>          bit_is_set( LN_RX_PORT, LN_RX_BIT ) )
>     {
>         ...
>     }

Likewise here since bit_is_set() is defined by avr-libc thusly:

  #define bit_is_set(sfr, bit)   (sfr & _BV(bit))

Again, I think replacing '==' with '&&' will correct the code.

Other than those logical errors, I think Neil's comments ring true.

Ted Roth



reply via email to

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