[Bug c/78317] New: "if (x & constant) z |= constant" should not be rendered with jumps and conditional moves
dhowells at redhat dot com
gcc-bugzilla@gcc.gnu.org
Fri Nov 11 15:55:00 GMT 2016
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=78317
Bug ID: 78317
Summary: "if (x & constant) z |= constant" should not be
rendered with jumps and conditional moves
Product: gcc
Version: 6.2.1
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: c
Assignee: unassigned at gcc dot gnu.org
Reporter: dhowells at redhat dot com
Target Milestone: ---
Created attachment 40025
--> https://gcc.gnu.org/bugzilla/attachment.cgi?id=40025&action=edit
Test code
The following code:
unsigned test1(unsigned x)
{
unsigned z = 0;
if (x & 0x10)
z |= 0x10;
return z;
}
on x86_64 compiled with -Os to:
0: 89 f8 mov %edi,%eax
2: ba 10 00 00 00 mov $0x10,%edx
7: 83 e0 10 and $0x10,%eax
a: 0f 45 c2 cmovne %edx,%eax
d: c3 retq
when what it should probable do is what clang does:
0: 83 e7 10 and $0x10,%edi
3: 89 f8 mov %edi,%eax
5: c3 retq
as the bit can be transferred by an AND and an OR.
Further, two or more such statements can be combined, for instance:
unsigned test2(unsigned x)
{
unsigned z = 0;
if (x & 0x10)
z |= 0x10;
if (x & 0x40)
z |= 0x40;
return z;
}
but gcc gives the following:
e: 89 f8 mov %edi,%eax
10: ba 10 00 00 00 mov $0x10,%edx
15: 83 e0 10 and $0x10,%eax
18: 0f 45 c2 cmovne %edx,%eax
1b: 89 c2 mov %eax,%edx
1d: 83 ca 40 or $0x40,%edx
20: 40 80 e7 40 and $0x40,%dil
24: 0f 45 c2 cmovne %edx,%eax
27: c3 retq
when clang gives:
6: 83 e7 50 and $0x50,%edi
9: 89 f8 mov %edi,%eax
b: c3 retq
If z isn't passed in, but rather is initialised to another argument, say y:
unsigned test3(unsigned x, unsigned y)
{
unsigned z = y;
if (x & 0x10)
z |= 0x10;
return z;
}
unsigned test4(unsigned x, unsigned y)
{
unsigned z = y;
if (x & 0x10)
z |= 0x10;
if (x & 0x40)
z |= 0x40;
return z;
}
then gcc gives:
0000000000000028 <test3>:
28: 89 f2 mov %esi,%edx
2a: 89 f0 mov %esi,%eax
2c: 83 ca 10 or $0x10,%edx
2f: 40 80 e7 10 and $0x10,%dil
33: 0f 45 c2 cmovne %edx,%eax
36: c3 retq
0000000000000037 <test4>:
37: 89 f2 mov %esi,%edx
39: 89 f0 mov %esi,%eax
3b: 83 ca 10 or $0x10,%edx
3e: 40 f6 c7 10 test $0x10,%dil
42: 0f 45 c2 cmovne %edx,%eax
45: 89 c2 mov %eax,%edx
47: 83 ca 40 or $0x40,%edx
4a: 40 80 e7 40 and $0x40,%dil
4e: 0f 45 c2 cmovne %edx,%eax
51: c3 retq
and clang gives:
000000000000000c <test3>:
c: 83 e7 10 and $0x10,%edi
f: 09 f7 or %esi,%edi
11: 89 f8 mov %edi,%eax
13: c3 retq
0000000000000014 <test4>:
14: 89 f8 mov %edi,%eax
16: 83 e0 10 and $0x10,%eax
19: 09 f0 or %esi,%eax
1b: 83 e7 40 and $0x40,%edi
1e: 09 c7 or %eax,%edi
20: 89 f8 mov %edi,%eax
22: c3 retq
Both gcc and clang give suboptimal code for test4(). What they should do is:
and $0x50,%edi
or %esi,%edi
mov %edi,%eax
retq
Note that gcc also produces similarly suboptimal output for targets other than
x86_64.
More information about the Gcc-bugs
mailing list