This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Rehash of force_to_mode bug


I am reposting a summary of the force_to_mode bug and patch in hopes that
someone will review the patch and approve it.

This is a pretty serious bug, and really should be addressed.

The full testcase and compiler options are in the message:

http://gcc.gnu.org/ml/gcc-patches/2001-02/msg01590.html

The testcase is basically:

int b = 5;

void main(void)

{
        int a = 0;

        if (b) {
                func();
        }

        printf("%d\n", (a + 23) & 0xfffffffc);
}

What happens is detailed in this message:

http://gcc.gnu.org/ml/gcc-bugs/2001-02/msg00630.html

but a full explanation of the problem is that gcc generates this rtx:

(and:SI (plus:SI (reg/v:SI 57)
        (const_int 23 [0x17]))
    (const_int 60 [0x3c]))

(reg:SI 57 is "int a" whiich is known to be zero)

and calls simplify_logical which strips off the top level and:SI 
and calls force_to_mode with the rtx:

(plus:SI (reg/v:SI 57)
        (const_int 23 [0x17]))

and the bitmask 0xfffffffc.

What happens next is that force_to_mode notices the low-order bits
can affect the result of the operation, so it widens the bitmask
using this code:

 /* When we have an arithmetic operation, or a shift whose count we
     do not know, we need to assume that all bit the up to the highest-order
     bit in MASK will be needed.  This is how we form such a mask.  */
  if (op_mode)
    fuller_mask = (GET_MODE_BITSIZE (op_mode) >= HOST_BITS_PER_WIDE_INT
                   ? GET_MODE_MASK (op_mode)
                   : ((HOST_WIDE_INT) 1 << (floor_log2 (mask) + 1)) - 1);
  else
    fuller_mask = ~ (HOST_WIDE_INT) 0;

which basically results in the bitmask being permanently lost, and the
expression winds up being simply (a + 23)

This is demonstrated in the output code in the message:

http://gcc.gnu.org/ml/gcc-bugs/2001-02/msg00658.html

I originally wrote a patch to simply disable the call to force_to_mode from
simplify_and_const_int, because it looks like force_to_mode was was originally written
to truncate useless high-order bits bits when an arithmetic operation was only used
at a narrower mode, e.g. an SImode expression which wound up being stored at HImode or
QImode.

I'm assuming that force_to_mode was originally designed to take an SImode rtx which
is only evaluated QImode or HImode, and remove the redundant computations in the
SImode rtx. If the QImode or HImode bitmask can't be propogated down into the SImode
rtx, then it's acceptable to lose the AND operation with the bitmask because the
final result will only be used at QImode/HImode anyway.

To beat a dead horse with an example:

    char a;
    int b, c;

    a = b + c;

Basically this winds up being a = (b + c) & 0x000000ff, and simplify_and_const_int
calls force_to_mode with (b + c) with the bitmask 0x000000ff. 

Next, simplify_and_const_int notices that it can't convert the expression to 
(a & 0x000000ff) + (b & 0x000000ff) because the low-order bits are significant,
so it widens the bitmask which effectively removes the AND operation. This doesn't 
matter in this case because the result is used at QImode.

However, it looks like someone modified force_to_mode to generically handle any
bitmask by having it widen the bitmask when the low-order bits affect the final
value. This is fine, however, the mask still needs to be applied to the final result
for the low-order bits to be properly zeroed!

My final revision of the patch which fixes force_to_mode instead of simply
disabling a call a to it is in the message:

http://gcc.gnu.org/ml/gcc-patches/2001-03/msg00374.html

This bug exists in all version of gcc I've checked including
gcc 2.95.x, 3.0 and the CVS head.

Toshi


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]