On 11/10/25 03:55, Richard Biener wrote:
On Fri, 7 Nov 2025, Andrew MacLeod wrote:
On 11/7/25 13:28, Richard Biener wrote:
Am 07.11.2025 um 15:46 schrieb Andrew MacLeod <[email protected]>:
On 11/7/25 08:29, Richard Biener wrote:
When feeding non-SSA names to range_on_edge we degrade to a
non-contextual query even though range_on_exits handling suggests
that we can do better. The following does what it does in
range_on_edge directly, passing the edge source as 'bbend'
argument to get_tree_range if the edge source has a single
successor (as will be the case for queries from niter analysis).
Bootstrapped on x86_64-unknown-linux-gnu, testing in progress.
OK? The remainder of the series makes use of this, I'll hold of
that a bit for followup work.
Yeah, That's good.
I did wonder whether the else path using range_on_exit is wrong in this
regard?
Richard
No it is correct
For the most part GORI calculates edge ranges for ssa-names independant of
their actual range. So this is combined with the range-on-exit from the
block, to produce the actual range on the edge.
ie, if (a > 100) GORI will produce [101, +INF] for the edge range of 'a'
on the true side.
It is combined with the on exit range of 'a' in the edges src block to
determine the true range of 'a' on an edge.,
range_on_exit (r, e->src, name);
<...>
if (m_cache.range_on_edge (edge_range, e, name))
r.intersect (edge_range);
In your path with a non-SSA name, its important to only use the on exit range
if there is a single successor since there will be no edge adjustment.
Hmm, but the above adjustment is intersection, it will make ranges only
smaller. There's also
well, it needs to. Ranges are only every reduced by an interaction.
Lets assume a_2 has been calculated to have a global range of [0, 100]
if the block exit is
if (a_2 > 40)
GORI will return [41, +INF].
on the true edge we need to intersect the exit range with the edge
range, and can then determine that a_2 on that edge is [41, 100]
// If this is not an abnormal edge, check for a non-null exit .
if ((e->flags & (EDGE_EH | EDGE_ABNORMAL)) == 0)
infer_oracle ().maybe_adjust_range (r, name, e->src);
at the <...>, not sure what that does.
Aggregates and applies any inferred ranges from within the block, like a
de-reference that causes non-zero, or what have you. It makes sure they
are applied to any ranges exiting the block
in our above example a_2 was [0, 100], if in the block also contained
b_6 = v_5 / a_2
there would be an inferred range applied of [-INF, -1][1, +INF] as
divide by zero ensures it cant be zero, and that make the range f a_2
[1, 100] at block exit rather than [0, 100]
That said, there's currently no worker for on_edge for GENERIC in GORI.
But this and the above means that even doing
if (!gimple_range_ssa_p (name))
res = get_tree_range (r, name, NULL, NULL, e->src);
should be correct.
yes, the on exit value is always correct, especially if there is no
branch. if there is a branch, you simply don't get the benefit of
potential range reduction on the edge.
Similarly doing get_tree_range (r, name, NULL,
e->dest, NULL) should produce correct answers, no? So I should be
No, that would no be the same. Range on entry is calculated by
aggregating (unioning) all the incoming edges. Lets assume b_3 is varying.
bb2:
if (b_3) > 100 goto bb5
bb3: // b_3 range on entry is [-INF, 100]
bb4: // b_3 is still [-INF, 100]
// bb4 falls through to bb5.
bb5: // b_3 range on entry is now VARYING.
for the edge 4->5 , exit range of bb4 is [-INF, 100], but the entry
range of bb5 is VARYING. because the branch in bb2 no longer dominates
the block.
so yes, for a single pred successor, the on entry is the same as the on
exit, but im not sure what value there is in checking.. just use the on
exit value always for get_tree_range.
Because its an expression rather than a specific SSA_NAME, there are no
callbacks into ranger for any ssa-names found in the expression, so the
only granularity we currently have is the on exit or on entry range...
the entry and exit blocks are late additions to solve some issues i
forget... I never really considered range on edge... I see no reason
not to add it if it is useful...
I attached a quick patch that should allow you to specify an edge.. try it.
able to remove the single_succ (e->src) requirement - in fact I'd
expect the most precise ranges when using the e->dest in case
there's a single predecessor because then (hopefully) GORI can do
work on mentioned SSA names in the GENERIC expression?
Well, if there is a single predecessor, yes, you may pick up the
outgoing edge range that way.
I'm testing
diff --git a/gcc/gimple-range.cc b/gcc/gimple-range.cc
index 942bf8bf0a5..cc474db6818 100644
--- a/gcc/gimple-range.cc
+++ b/gcc/gimple-range.cc
@@ -252,8 +252,12 @@ gimple_ranger::range_on_edge (vrange &r, edge e, tree
name)
bool res = true;
if (!gimple_range_ssa_p (name))
- res = get_tree_range (r, name, NULL, NULL,
- single_succ_p (e->src) ? e->src : NULL);
+ {
+ if (single_pred_p (e->dest)
+ res = get_tree_range (r, name, NULL, e->dest, NULL);
+ else
+ res = get_tree_range (r, name, NULL, NULL, e->src);
+ }
else
{
range_on_exit (r, e->src, name);
there's the twist that at e->dest not all mentioned SSA names might
be defined in a dominating position, so this would be an argument
against using e->dest. But then always using e->src should be still
correct?
Thanks,
Richard.
If you find that patch useful, feel free to commit it with your other
changes
Andrew
diff --git a/gcc/value-query.cc b/gcc/value-query.cc
index c4e50834646..194a3ffa41c 100644
--- a/gcc/value-query.cc
+++ b/gcc/value-query.cc
@@ -294,18 +294,24 @@ range_query::~range_query ()
bool
range_query::invoke_range_of_expr (vrange &r, tree expr, gimple *stmt,
- basic_block bbentry, basic_block bbexit)
+ basic_block bbentry, basic_block bbexit,
+ edge e)
{
if (bbentry)
{
- gcc_checking_assert (!stmt && !bbexit);
+ gcc_checking_assert (!stmt && !bbexit && !e);
return range_on_entry (r, bbentry, expr);
}
if (bbexit)
{
- gcc_checking_assert (!stmt);
+ gcc_checking_assert (!stmt && !e);
return range_on_exit (r, bbexit, expr);
}
+ if (e)
+ {
+ gcc_checking_assert (!stmt);
+ return range_on_edge (r, e, expr);
+ }
return range_of_expr (r, expr, stmt);
}
@@ -316,7 +322,7 @@ range_query::invoke_range_of_expr (vrange &r, tree expr, gimple *stmt,
bool
range_query::get_tree_range (vrange &r, tree expr, gimple *stmt,
- basic_block bbentry, basic_block bbexit)
+ basic_block bbentry, basic_block bbexit, edge e)
{
tree type;
if (TYPE_P (expr))
@@ -364,7 +370,7 @@ range_query::get_tree_range (vrange &r, tree expr, gimple *stmt,
case SSA_NAME:
// If this is not an abnormal or virtual ssa, invoke range_of_expr.
if (gimple_range_ssa_p (expr))
- return invoke_range_of_expr (r, expr, stmt, bbentry, bbexit);
+ return invoke_range_of_expr (r, expr, stmt, bbentry, bbexit, e);
gimple_range_global (r, expr);
return true;
@@ -402,8 +408,8 @@ range_query::get_tree_range (vrange &r, tree expr, gimple *stmt,
{
value_range r0 (TREE_TYPE (op0));
value_range r1 (TREE_TYPE (op1));
- invoke_range_of_expr (r0, op0, stmt, bbentry, bbexit);
- invoke_range_of_expr (r1, op1, stmt, bbentry, bbexit);
+ invoke_range_of_expr (r0, op0, stmt, bbentry, bbexit, e);
+ invoke_range_of_expr (r1, op1, stmt, bbentry, bbexit, e);
if (!op.fold_range (r, type, r0, r1))
r.set_varying (type);
}
@@ -421,7 +427,7 @@ range_query::get_tree_range (vrange &r, tree expr, gimple *stmt,
value_range r1 (type);
r1.set_varying (type);
invoke_range_of_expr (r0, TREE_OPERAND (expr, 0), stmt, bbentry,
- bbexit);
+ bbexit, e);
if (!op.fold_range (r, type, r0, r1))
r.set_varying (type);
}
diff --git a/gcc/value-query.h b/gcc/value-query.h
index ee648709199..eb5b867fc84 100644
--- a/gcc/value-query.h
+++ b/gcc/value-query.h
@@ -92,9 +92,10 @@ public:
protected:
bool get_tree_range (vrange &v, tree expr, gimple *stmt,
- basic_block bbentry = NULL, basic_block bbexit = NULL);
+ basic_block bbentry = NULL, basic_block bbexit = NULL,
+ edge e = NULL);
bool invoke_range_of_expr (vrange &v, tree expr, gimple *stmt,
- basic_block bbentry, basic_block bbexit);
+ basic_block bbentry, basic_block bbexit, edge e);
bool get_arith_expr_range (vrange &r, tree expr, gimple *stmt);
relation_oracle *m_relation;
infer_range_oracle *m_infer;