[Bug middle-end/78103] Failure to optimize with __builtin_clzl

jakub at gcc dot gnu.org gcc-bugzilla@gcc.gnu.org
Sat Jul 24 12:28:42 GMT 2021


https://gcc.gnu.org/bugzilla/show_bug.cgi?id=78103

--- Comment #8 from Jakub Jelinek <jakub at gcc dot gnu.org> ---
I actually think this should be doable with combiner splitters.
For the
unsigned int findLastSet3(unsigned long x) {
  return x ? 8 * sizeof(unsigned long) - __builtin_clzl(x) : 0;
}
or
unsigned int findLastSet4(unsigned int x) {
  return x ? 8 * sizeof(unsigned int) - __builtin_clz(x) : 0;
}
the combiner sees everything together, in the first case
(parallel [
        (set (reg:SI 84 [ <retval> ])
            (minus:SI (const_int 64 [0x40])
                (xor:SI (minus:SI (const_int 63 [0x3f])
                        (subreg:SI (clz:DI (reg/v:DI 85 [ x ])) 0))
                    (const_int 63 [0x3f]))))
        (clobber (reg:CC 17 flags))
    ])
and in the latter case
(parallel [
        (set (reg/v:SI 85 [ x ])
            (minus:SI (const_int 32 [0x20])
                (xor:SI (minus:SI (const_int 31 [0x1f])
                        (clz:SI (reg/v:SI 85 [ x ])))
                    (const_int 31 [0x1f]))))
        (clobber (reg:CC 17 flags))
    ])
so we just need to split it - into bsr and add 1 (of course only if
!TARGET_LZCNT, otherwise it is defined even for 0 and we don't know that it
will be UB on zero).
For the #c0 findLastSet we don't know that, but again we should know that it is
UB at zero when !TARGET_LZCNT and so we could first split
(set (reg:DI 87 [ _1 ])
    (xor:DI (sign_extend:DI (minus:SI (const_int 63 [0x3f])
                (subreg:SI (clz:DI (reg/v:DI 85 [ x ])) 0)))
        (const_int 63 [0x3f])))
into bsr and xor (i.e. get rid of the sign extension, if it is UB at zero, then
we know clz will be in range 0 to 63 and sign extension or zero extension are
the same and performed already when using the bs{q,l} instruction.


More information about the Gcc-bugs mailing list