As observed at http://blog.regehr.org/archives/320 (example 7) testcase: int crud (unsigned char c) { return (((((((((((int) c <= 32 || (int) c == 46) || (int) c == 44) || (int) c == 58) || (int) c == 59) || (int) c == 60) || (int) c == 62) || (int) c == 34) || (int) c == 92) || (int) c == 39) != 0); } Can be compiled using shift and mask test operation as: crud: movzbl %dil, %edi cmpl $32, %edi jle ..B1.4 addl $-34, %edi cmpl $64, %edi jae ..B1.5 movl $1, %eax movl %edi, %ecx shlq %cl, %rax movq $0x400000017001421, %rdx testq %rdx, %rax je ..B1.5 ..B1.4: movl $1, %eax ret ..B1.5: xorl %eax, %eax ret Probably switch conversion pass could be responsible for this. Honza
Note that both llvm and ICC support this optimization and it was requested by kernel folks for a while (they do so by hand)
We probably don't want to do such transformation into GIMPLE_SWITCH always, only if the number of comparisons of the same SSA_NAME is big enough and the range isn't too big. expand_switch_using_bit_tests_p can be used if we want to limit it just to the bittest cases.
I would do the conversion always when we can turn more than one if into signle switch. Doing so reduces the amount of IL and makes program easier to analyze&opotimize. We should rely on switch expansion code doing the right thing producing back the ifs when profitable.
I know Tom de Vries is working on this problem and has a prototype patch. He'll be posting his work for 4.7.
> I know Tom de Vries is working on this problem and has a prototype patch. > He'll be posting his work for 4.7. http://gcc.gnu.org/ml/gcc-patches/2011-01/msg00959.html
Related bug: PR 14799.
(In reply to Tom de Vries from comment #5) > > I know Tom de Vries is working on this problem and has a prototype patch. > > He'll be posting his work for 4.7. > > http://gcc.gnu.org/ml/gcc-patches/2011-01/msg00959.html Does it still apply for gcc 9?
The test-case is still valid.
(In reply to Martin Liška from comment #8) > The test-case is still valid. Sorry, no, the issue is already solved with GCC 9.2: crud (unsigned char c) { _Bool _11; int iftmp.0_14; int _16; long unsigned int _24; _Bool _26; int _30; long unsigned int _32; <bb 2> [local count: 1073741823]: if (c_15(D) > 62) goto <bb 4>; [50.00%] else goto <bb 3>; [50.00%] <bb 3> [local count: 536870911]: _16 = (int) c_15(D); _24 = 6629387187945209855 >> _16; _32 = ~_24; _26 = (_Bool) _32; if (_26 != 0) goto <bb 4>; [20.00%] else goto <bb 5>; [80.00%] <bb 4> [local count: 536870911]: _11 = c_15(D) == 92; _30 = (int) _11; <bb 5> [local count: 1073741824]: # iftmp.0_14 = PHI <_30(4), 1(3)> return iftmp.0_14; }