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.