[Bug tree-optimization/64567] New: missed optimization: redundant test before clearing bit(s)
rv at rasmusvillemoes dot dk
gcc-bugzilla@gcc.gnu.org
Mon Jan 12 13:15:00 GMT 2015
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=64567
Bug ID: 64567
Summary: missed optimization: redundant test before clearing
bit(s)
Product: gcc
Version: unknown
Status: UNCONFIRMED
Severity: enhancement
Priority: P3
Component: tree-optimization
Assignee: unassigned at gcc dot gnu.org
Reporter: rv at rasmusvillemoes dot dk
(Not sure the "Component" is correct). gcc fails to optimize
if (foo & FLAG)
foo &= ~FLAG;
into simply unconditionally doing foo &= ~FLAG. Currently, the above code
sequence generates four instructions (mov, and, test, cmov) whereas a single
and would be sufficient. Note that this is a valid transformation regardless of
how many bits are set in FLAG; it doesn't even have to be a compile-time
constant (but must of course be side-effect free).
gcc also doesn't optimize the dual
if (!(foo & FLAG))
foo |= FLAG;
into foo |= FLAG;. That transformation is however only valid when FLAG is known
to consist of only a single bit (so would probably require either a
compile-time constant where this can be checked or an expression of the form "1
<< something").
Trivial test case below. I'd expect foo and foo2 to compile to the same code,
and similarly for baz and baz2.
$ cat test.c
#define F1 0x04
#define F2 0x08
int bar(unsigned flags);
int foo(unsigned flags)
{
if (flags & (F1 | F2))
flags &= ~(F1 | F2);
return bar(flags);
}
int foo2(unsigned flags)
{
flags &= ~(F1 | F2);
return bar(flags);
}
int baz(unsigned flags)
{
if (!(flags & F1))
flags |= F1;
return bar(flags);
}
int baz2(unsigned flags)
{
flags |= F1;
return bar(flags);
}
$ ./gcc-5.0 -Wall -Wextra -O3 -c test.c
$ objdump -d test.o
test.o: file format elf64-x86-64
Disassembly of section .text:
0000000000000000 <foo>:
0: 89 f8 mov %edi,%eax
2: 83 e0 f3 and $0xfffffff3,%eax
5: 40 f6 c7 0c test $0xc,%dil
9: 0f 45 f8 cmovne %eax,%edi
c: e9 00 00 00 00 jmpq 11 <foo+0x11>
11: 66 66 66 66 66 66 2e data32 data32 data32 data32 data32 nopw
%cs:0x0(%rax,%rax,1)
18: 0f 1f 84 00 00 00 00
1f: 00
0000000000000020 <foo2>:
20: 83 e7 f3 and $0xfffffff3,%edi
23: e9 00 00 00 00 jmpq 28 <foo2+0x8>
28: 0f 1f 84 00 00 00 00 nopl 0x0(%rax,%rax,1)
2f: 00
0000000000000030 <baz>:
30: 89 f8 mov %edi,%eax
32: 83 c8 04 or $0x4,%eax
35: 40 f6 c7 04 test $0x4,%dil
39: 0f 44 f8 cmove %eax,%edi
3c: e9 00 00 00 00 jmpq 41 <baz+0x11>
41: 66 66 66 66 66 66 2e data32 data32 data32 data32 data32 nopw
%cs:0x0(%rax,%rax,1)
48: 0f 1f 84 00 00 00 00
4f: 00
0000000000000050 <baz2>:
50: 83 cf 04 or $0x4,%edi
53: e9 00 00 00 00 jmpq 58 <baz2+0x8>
More information about the Gcc-bugs
mailing list