Hi all,

I'm looking into PR 54168 where we end up generating an unnecessary extend operation on arm.

Given code:

struct b2Body {
    unsigned short flags;
    int type;
};

static  _Bool IsAwake(struct b2Body *b)
{
    return (b->flags & 2) == 2;
}


int foo(struct b2Body *bA, struct b2Body *bB)
{
    int typeA = bA->type;
    int typeB = bB->type;
    _Bool activeA = IsAwake(bA) && typeA != 0;
    _Bool activeB = IsAwake(bB) && typeB != 0;

    if (!activeA && !activeB)
    {
        return 1;
    }

    return 0;
}

Compiled for arm-none-eabi with -O3 -march=armv7-a

The inlined generated code for IsAwake contains the fragment:

        ldrh    r0, [r1]
        and     r0, r0, #2
        uxth    r0, r0
        cmp     r0, #0

which contains a redundant extend, which also confuses combine and prevents the whole thing from being optimised into an ldrh ; ands sequence.

Looking at the tree dumps I notice that after the forwprop pass the types of the operands in the _7 = _3 & 2; statement turn into short unsigned where before that pass they were just ints:

IsAwake (struct b2Body * b)
{
  short unsigned int _3;
  int _4;
  _Bool _6;
  short unsigned int _7;

  <bb 2>:
  _3 = b_2(D)->flags;
  _4 = (int) _3;
  _7 = _3 & 2;
  _6 = _7 != 0;
  return _6;

}


I believe the C standard expects the operation to be performed in int mode. Now, since this is a bitwise and operation with a known constant 2, the operation can be safely performed in unsigned short mode. However on word-based machines like arm this would introduce unnecessary extend operations down the line, as I believe is the case here.

Anyone have any insight on how to resolve this one?

Thanks,
Kyrill

Reply via email to