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

--- Comment #8 from GCC Commits <cvs-commit at gcc dot gnu.org> ---
The master branch has been updated by Kyrylo Tkachov <[email protected]>:

https://gcc.gnu.org/g:bbac87391e456997bd389bcbda8f2fcb734f922d

commit r17-5342-gbbac87391e456997bd389bcbda8f2fcb734f922d
Author: Kyrylo Tkachov <[email protected]>
Date:   Mon Oct 12 04:14:47 2026 -0700

    niter: Give the complement counts a value at zero [PR111280]

    number_of_iterations_cltz_complement handles loops that shift an IV
    until it is zero.  If the start value T of the IV can be zero and the
    target does not define .CLZ at zero, build_cltz_expr builds
    T != 0 ? .CLZ (T) : PREC.  The final value replacement gimplifies the
    count before the select, so .CLZ (T) is also evaluated for a zero T,
    where its result is undefined.  For sqrtllu in
    gcc.c-torture/execute/920501-6.c, sccp on x86_64 emits

      _28 = t_10(D) != 0;
      _27 = .CLZ (t_10(D));
      _22 = (unsigned int) _27;
      _29 = 64 - _22;
      _23 = (long long unsigned int) _29;
      b_30 = _28 ? _23 : 1;

    The expansion now implements any value at zero.  As Richard Biener
    suggested in PR111280 comment 6, build .CLZ (T, PREC) instead of the
    select.

    The loop in sqrtllu modifies the IV before the exit test.  For such
    loops the number of iterations was PREC - 1 - .CLZ (T), with another
    select for a zero T.  The first value that the loop tests is T >> 1
    (T << 1 for CTZ), and PREC minus the count of that value is right for
    all T.  Use it and drop the select:

      _27 = t_10(D) >> 1;
      _28 = .CLZ (_27, 64);
      _39 = 65 - _28;
      b_30 = (long long unsigned int) _39;

    If the conditions on entry to the loop show that T is not zero, the
    count needs no value at zero.  simplify_using_initial_conditions removed
    the select in that case, so ask it before the count is built.  Guarded
    loops, which include while loops after header copying, keep their code.

    sqrtllu has 17 instead of 19 instructions on aarch64 and 23 instead of
    25 on x86_64 with -march=x86-64-v3.  Without LZCNT it has 26 instead of
    22 on x86_64, because the expansion of .CLZ (_27, 64) tests _27.

    Types without a .CLZ or .CTZ internal function use the builtins with a
    select, as before.  The argument can now be a shift, so unshare it in
    the select, because final value replacement rejects shared trees.

    Bootstrapped and tested on aarch64-none-linux-gnu and x86_64-linux.

    gcc/ChangeLog:

            PR tree-optimization/111280
            * tree-ssa-loop-niter.cc (build_cltz_expr): Pass the precision
            as the value at zero of the internal function instead of a
            select.  Unshare SRC in the select of the builtins.
            (number_of_iterations_cltz_complement): Ask for a value at zero
            only if SRC can be zero on entry.  If the IV is modified before
            the test and SRC can be zero, count the zeros of the first value
            tested.

    gcc/testsuite/ChangeLog:

            PR tree-optimization/111280
            * gcc.dg/tree-ssa/pr111280.c: New test.

    Signed-off-by: Kyrylo Tkachov <[email protected]>

Reply via email to