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