[Top][All Lists]

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

[avr-gcc-list] Re: char to int promotion in bitwise operators

From: David Brown
Subject: [avr-gcc-list] Re: char to int promotion in bitwise operators
Date: Mon, 24 Aug 2009 14:35:20 +0200
User-agent: Thunderbird (Windows/20090605)

Andrew Zabolotny wrote:
From Fri, 21 Aug 2009 21:35:39 +0200 (MET DST)
address@hidden (Joerg Wunsch) wrote:

Francisco Silva <address@hidden> wrote:
Try the following spell:
Using a typecast looks a little better, I think.
Looks better, but does not work. But Francisco recipe works, wonders.
Another solution which works is your hint about inline functions, e.g:

static inline uint8_t dummy (uint8_t x) { return x; }

if (dummy (flags & (FLAG_A | FLAG_B))) ...

what's interesting as well is that I have two of such if's in code, and
"fixing" the first one automagically fixes the second if without making
any actual modifications to it.

Andrew, maybe you can post some compilable code snippet to check.
Sure, I've attached a bare-bone sample which I can't force to use eight
bits without the temporary variable or inline function hack.

The problem, I believe, boils down to C demanding that everything gets promoted to 16-bit ints, and then the AVR-specific peephole optimiser tries to remove unnecessary code and bring things back down to 8 bits. The peepholer is good, but not perfect, and it misses some optimisations. Some of these are on the "things to do list" (and Eric will tell you that the list of "things" is long, but the list of "doers" is short). The most common cases, such as testing for a single flag, generally do produce optimal code.

Sometimes odd changes to the code can give you better results in the end because the intermediate RTL code happens to match a peepholer pattern (you can easily get different sequences of internal RTL code that translate to the same resulting assembly, making it hard to understand if you only see the source C and the end assembly code). This seems to be the case with the inline function hack.

Another idea is to use a C++ class for the flag bytes. It may sound counter to common beliefs, but this can actually be a better solution because C++ does not require 8-bit classes to be promoted to 16-bit ints (though the promotion is still required in parts of the implementation). I believe (but haven't confirmed) that this means that the compiler has the data as 8 bits for more of its lifetime in internal representations, and therefore has a better chance of producing optimal code. I've only played around with this a little, but this version produces optimal 8-bit code (the same as the C code with the inline hack) :

class byte {
        private :
                uint8_t v;
        public :
                byte(uint8_t x = 0) : v (x) { };

                operator uint8_t() const { return v; };
                byte& operator += (byte b) { v += b.v; return *this; };
                byte& operator |= (byte b) { v |= b.v; return *this; };
                byte operator & (byte b) { return v & b.v; };


void tty_setup (uint8_t flags, uint8_t mask)
    uint8_t new_flags = (tty_flags & ~mask) | (flags & mask);
    byte flags_changed = new_flags ^ tty_flags;
    tty_flags = new_flags;

if (flags_changed & byte(TTY_F_DISPLAY | TTY_F_CURSOR | TTY_F_BLINKCURSOR))
        something ();

    if (flags_changed & byte(TTY_F_SCROLL | TTY_F_L2R))
        somethingelse ();

reply via email to

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