Bug 103457 - boolean operations on bit-fields are not merged
Summary: boolean operations on bit-fields are not merged
Status: ASSIGNED
Alias: None
Product: gcc
Classification: Unclassified
Component: tree-optimization (show other bugs)
Version: 12.0
: P3 enhancement
Target Milestone: 13.4
Assignee: Andrew Pinski
URL:
Keywords: missed-optimization
Depends on:
Blocks: bitfield
  Show dependency treegraph
 
Reported: 2021-11-28 19:58 UTC by Roland Illig
Modified: 2024-05-21 09:10 UTC (History)
1 user (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2021-11-28 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Roland Illig 2021-11-28 19:58:59 UTC
~~~c
#include <stdbool.h>

typedef struct GNodeFlagsS {
	bool remake:1;
	bool childMade:1;
	bool force:1;
	bool doneWait:1;
	bool doneOrder:1;
	bool fromDepend:1;
	bool doneAllsrc:1;
	bool cycle:1;
	bool doneCycle:1;
} GNodeFlags;

bool
GNodeFlags_IsNone(GNodeFlags flags)
{
	return !flags.remake
	       && !flags.childMade
	       && !flags.force
	       && !flags.doneWait
	       && !flags.doneOrder
	       && !flags.fromDepend
	       && !flags.doneAllsrc
	       && !flags.cycle
	       && !flags.doneCycle;
}
~~~

On x86_64, GCC 11.2 generates:

~~~asm
GNodeFlags_IsNone(GNodeFlagsS):
        mov     eax, edi
        and     eax, 1
        jne     .L6
        test    dil, 2
        jne     .L1
        mov     eax, edi
        shr     ax, 2
        and     eax, 1
        jne     .L6
        test    dil, 8
        jne     .L1
        mov     eax, edi
        shr     ax, 4
        and     eax, 1
        jne     .L6
        test    dil, 32
        jne     .L1
        mov     eax, edi
        shr     ax, 6
        and     eax, 1
        jne     .L6
        test    dil, dil
        js      .L1
        shr     di, 8
        mov     eax, edi
        and     eax, 1
        xor     eax, 1
        ret
.L6:
        xor     eax, eax
.L1:
        ret
~~~

ICC 2021.3.0 generates shorter code:

~~~asm
        test      edi, 1                                        #18.10
        jne       ..B1.10       # Prob 50%                      #18.10
        test      edi, 2                                        #19.13
        jne       ..B1.10       # Prob 50%                      #19.13
        test      edi, 4                                        #20.13
        jne       ..B1.10       # Prob 50%                      #20.13
(and so on)
~~~

Many other compilers fail to see the potential for optimizing this code as well.

Clang is better, it generates:

~~~asm
GNodeFlags_IsNone(GNodeFlagsS):     # @GNodeFlags_IsNone(GNodeFlagsS)
        test    edi, 511
        sete    al
        ret
~~~
Comment 1 Andrew Pinski 2021-11-28 22:27:02 UTC
Mine for GCC 13. There is other bugs which are similar too.
Comment 2 Roland Illig 2021-11-28 23:20:18 UTC
Cool, thank you for taking this optimization.

Just to give you a bit of background: I discovered this while converting some of the enum types in BSD Make to proper bitfields, which theoretically should be possible without affecting the generated code.

https://github.com/NetBSD/src/blob/trunk/usr.bin/make/make.h

It was interesting to play around with this code on https://godbolt.org/, seeing how differently the available compilers translate this simple code fragment. That's where the Intel assembler syntax comes from. :)
Comment 3 Richard Biener 2023-04-26 06:55:35 UTC
GCC 13.1 is being released, retargeting bugs to GCC 13.2.
Comment 4 Richard Biener 2023-07-27 09:22:32 UTC
GCC 13.2 is being released, retargeting bugs to GCC 13.3.
Comment 5 Jakub Jelinek 2024-05-21 09:10:57 UTC
GCC 13.3 is being released, retargeting bugs to GCC 13.4.