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: Neil Johnson
Subject: Re: [avr-gcc-list] 8 bit bitwise operation promoted to 16 bit values
Date: Mon, 27 Oct 2003 11:16:30 +0000 (GMT)

Hi,

> I don't know why this seems to be so hard for people to get correct.
> [snip]
> What is really needed here is an ^^ operator:
>     if ( (LN_TX_PORT & ( 0x01 << LN_TX_BIT )) ^^
>         (LN_RX_PORT & ( 0x01 << LN_RX_BIT )) ) ...

Well, given the extra details supplied by Alex, this could be rewritten as

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

The required test is that the same bits in two different variables are the
same.  This is exactly _why_ I did not comment on the logic of the
problem: because there was insufficient information to say whether it was
right or not.  The question was how to write it to help the optimizer spot
that it could be done in 8-bit ops.

> Of course, that doesn't exist, so you have to write it out manually.  It
> could be written neater with macros, but if you only need it once (or can
> put it in an inline function, for example), then it doesn't matter that it's
> a bit ugly (assuming I've got the brackets right :-) :
>
>     if ( ((LN_TX_PORT & ( 0x01 << LN_TX_BIT )) &&
>         (LN_RX_PORT & ( 0x01 << LN_RX_BIT )) ) ||
>          (! (LN_TX_PORT & ( 0x01 << LN_TX_BIT )) &&
>           ! (LN_RX_PORT & ( 0x01 << LN_RX_BIT )) ) ) ...
>
> That will give you minimal bit-test instruction code.  It might also be
> neater, clearer and more useful to split it into a nested if, testing each
> bit individually.  Perhaps you can distinguish between 1/0 and 0/1 error
> cases ?

If you want to write it in that style, can I suggest the following:

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

The ! converts the value into a boolean (0 or 1) so we can then reliably
apply the == test.

> It never helps to use (byte) on something that is already a byte.  This is
> not quite the same as the earlier case, but again you are suffering from the
> C rule "when in doubt, promote to integer",

Actually, that is not a C rule, but a misunderstanding.  The language
clearly states what the promotion rules are for operators.

> and you are getting it because you are making the processor do all the
> work.  When faced with "x << y", where x and y are not both constants,
> the compiler has no choice but to use ints.  That's the way C works,

Erm, sorry.  The language standard clearly states:

C99 sect. 6.5.7: (para. 3 & 4):

  "The integer promotions are performed on each of the operands. The type
  of the result is that of the promoted left operand. If the value of the
  right operand is negative or is greater than or equal to the width of
  the promoted left operand, the behavior is undefined.

  The result of E1 << E2 is E1 left-shifted E2 bit positions; vacated bits
  are filled with zeros. If E1 has an unsigned type, the value of the
  result is E1 x 2^E2, reduced modulo one more than the maximum value
  representable in the result type. If E1 has a signed type and
  nonnegative value, and E1 x 2^E2 is representable in the result type,
  then that is the resulting value; otherwise, the behavior is undefined."

> like it or not (I don't).  The compiler doesn't know that BitIndex is
> always less than 4 - this would require pretty advanced code analysis,

Not exactly _that_ advanced.  Any modern book on compiler optimization
discusses loop index variables and range analysis.  In the code given it
is trivial to determine that the range of BitIndex is 0..3.  The compiler
can use this to determine, for example, that there is at least one
iteration of the loop and so elide the first branch to the test code.
This is analysis is already in GCC (judging by the generated code);
whether it is used as effectively as it could be is another matter,
something for you to discuss with the GCC optimizer writers...

> and anyway you have a function call within the loop - C cannot assume
> that the function does not modify the local variable

Yes it can---its called escape analysis.  In this instance the compiler
should be able to determine that the code never takes the address of
BitIndex.  It could use this information to keep BitIndex in a
callee-preserved register.

> (because C is a stupid language designed to save keystrokes, not a
> language designed for safe usage and optimal code generation).

Really?  Interesting...

> So the compiler has to follow the rules and use 16-bit code, even though
> it will then drop the high byte.

The compiler follows (the rules and) what the programmer puts in.  If the
programmer does not understand the rules, there's not a lot the compiler
can do about it.

Cheers,
Neil

--
Neil Johnson :: Computer Laboratory :: University of Cambridge ::
http://www.njohnson.co.uk          http://www.cl.cam.ac.uk/~nej22
----  IEE Cambridge Branch: http://www.iee-cambridge.org.uk  ----


reply via email to

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