On 10/27/25 10:25, Robin Dapp wrote:
Hmm, code does not match comment? I think you want r.nonzero_p ().
But that also means that at (*) we cannot simply leave 'r' to be the
range of the unshifted src.
+ assumptions = boolean_true_node;
+ }
+
+ /* If that didn't work use simplify_using_initial_conditions. */
+ if (assumptions == boolean_false_node)
Yeah, I originally used the path-based ranger and had an inverse condition.
Then I removed it and swapped the condition, realizing that things still work.
But they don't actually... as only a path-based approach has enough information
but the boundary conditions here are constricted enough that my test case still
passes (similar to v1) because nonzero_p is also the wrong check...
I re-introduced the path-based approach now, using a helper function, and
re-tested everything on x86, rv64gcv_zvl512b, and power10 in the attached v3.
Regards
You should not need path ranger to do this, a normal ranger should be
enough.
+/* Helper for number_of_iterations_cltz that uses path-based ranger to
+ determine if SRC, shifted left (when LEFT_SHIFT is true) or right
+ by NUM_IGNORED_BITS, is guaranteed to be != 0 inside LOOP.
+ Return true if so or false otherwise. */
+
+static bool
+shifted_range_nonzero_p (loop_p loop, tree src,
+ bool left_shift, int num_ignored_bits)
+{
+ int_range_max r (TREE_TYPE (src));
+ gcc_assert (num_ignored_bits >= 0);
+
+ auto_vec<basic_block, 2> path;
+ path.safe_push (loop->header);
+ path.safe_push (loop_preheader_edge (loop)->src);
+
+ bool range_nonzero = false;
+ gimple_ranger ranger;
+ path_range_query query (ranger, path);
+
+ if (query.range_of_expr (r, src)
THis will only pick up a global value for src. If I look at where ou
are calling from,
tree src = gimple_phi_arg_def (phi, loop_preheader_edge (loop)->dest_idx);
I presume what you are looking for is the value of src coming in on that
edge?
in which case you should only have to do
if (get_range_query (cfun)->range_on_edge (r, loop_preheader_edge
(loop), src))
to get the range.. which is what you were doing in the original patch.
In the latest version of the patch that doesn't use the path ranger, is
there an active ranger? (ie, the enable_ranger () call) . If not, all
you will get is global values again.
Whats the current version of the patch, using the get_range_query()->
range_on_edge () ?
Andrew
+ && !r.varying_p ()
+ && !r.undefined_p ())
+ {
+ if (num_ignored_bits)
+ {
+ range_op_handler op (left_shift ? LSHIFT_EXPR : RSHIFT_EXPR);
+ int_range_max shifted_range (TREE_TYPE (src));
+ wide_int shift_count = wi::shwi (num_ignored_bits,
+ TYPE_PRECISION (TREE_TYPE
+ (src)));
+ int_range_max shift_amount
+ (TREE_TYPE (src), shift_count, shift_count);
+
+ if (op.fold_range (shifted_range, TREE_TYPE (src), r,
+ shift_amount))
+ r = shifted_range;
+ }
+
+ /* If the range does not contain zero we are good. */
+ if (!range_includes_zero_p (r))
+ range_nonzero = true;
+ }
+
+ return range_nonzero;
+}
+
+
/* See comment below for number_of_iterations_bitcount.
For c[lt]z, we have:
@@ -2438,6 +2487,9 @@ number_of_iterations_cltz (loop_p loop, edge exit,
tree src = gimple_phi_arg_def (phi, loop_preheader_edge (loop)->dest_idx);
int src_precision = TYPE_PRECISION (TREE_TYPE (src));
+ /* Save the original SSA name before preprocessing for ranger queries. */
+ tree unshifted_src = src;
+
/* Apply any needed preprocessing to src. */
int num_ignored_bits;
if (left_shift)
@@ -2463,10 +2515,56 @@ number_of_iterations_cltz (loop_p loop, edge exit,
expr = fold_convert (unsigned_type_node, expr);
- tree assumptions = fold_build2 (NE_EXPR, boolean_type_node, src,
- build_zero_cst (TREE_TYPE (src)));
+ /* If the copy-header (ch) pass peeled one iteration we're shifting
+ SRC by preprocessing it above.
+
+ A loop like
+ if (bits)
+ {
+ while (!(bits & 1))
+ {
+ bits >>= 1;
+ cnt += 1;
+ }
+ return cnt;
+ }
+ ch (roughly) transforms into:
+ if (bits)
+ {
+ if (!(bits & 1)
+ {
+ do
+ {
+ bits >>= 1;
+ cnt += 1;
+ } while (!(bits & 1));
+ }
+ else
+ cnt = 1;
+ return cnt;
+ }
+
+ Then, our preprocessed SRC (that is used for c[tl]z computation)
+ will be bits >> 1, and the assumption is bits >> 1 != 0. */
+
+ /* As we don't have a gimple statement to query, use a path-based range
+ query from the preheader to the loop header to get the range of the
+ unshifted SRC, then apply the shift manually and check if the
+ resulting range is != 0. */
+ tree assumptions;
+ if (shifted_range_nonzero_p (loop, unshifted_src,
+ left_shift, num_ignored_bits))
+ assumptions = boolean_true_node;
+ else
+ {
+ /* If ranger couldn't prove the assumption, try
+ simplify_using_initial_conditions. */
+ assumptions = fold_build2 (NE_EXPR, boolean_type_node, src,
+ build_zero_cst (TREE_TYPE (src)));
+ assumptions = simplify_using_initial_conditions (loop, assumptions);
+ }
- niter->assumptions = simplify_using_initial_conditions (loop, assumptions);
+ niter->assumptions = assumptions;
niter->may_be_zero = boolean_false_node;
niter->niter = simplify_using_initial_conditions (loop, expr);