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]>
