On Fri, 6 Jun 2025, Andrew MacLeod wrote:

> 
> Interesting.
> 
> I don't remember details about the order of things...  Is there any chance
> that you might query an SSA_NAME whose DEF was in  a block which has been
> converted to RTL?   Ranger will query all the way back to the def block,
> accessed via gimple_bb (SSA_NAME_DEF_STMT (name)), or top of program looking
> for it. But I presume that won't happen?  You wouldn't get anything wrong,
> just inefficient.
> 
> Can't switches already have their default removed in simplification if the
> range of the switch index is completely covered by case labels?  
> From simplify_using_ranges::simplify_switch_using_ranges :
> 
>   /* Add the default edge, if necessary.  */
>   if (take_default)
>     TREE_VEC_ELT (vec2, n2++) = gimple_switch_default_label (stmt);
> 
> Although when I look at the result, it appears like the first case gets turned
> into the new default... so what do I know :-)
> 
> Otherwise I have no issues.    Ranger is primarily data propagation around the
> CFG.   range-ops doesn't care where the range comes from.  Its just the middle
> layer which interfaces ranger to GIMPLE that you are tweaking to be tolerant
> of non-gimple, and I'm sure that is manageable.
> 
> After writing this, I got to thinking...   Is expansion done in dominator
> order?  if so, perhaps you'd be better off using the dom_ranger that is used
> by the fast_vrp pass.   It works kinda like the way old EVRP works, in that it
> remembers all the ranges as it exits blocks, and disposes of them away when
> they are no longer needed.  Basically, as you march through the IL it never
> looks  backwards. All range_on_entry calls are satisfied by available exit
> blocks from predecessors.   You lose anything significant you might glean from
> back edges, but its still capable of most things ranger does, including
> relations and such.  Its currently used whenever the basic block count gets
> large, so its in production already.

I'm also a bit nervous about this given during RTL expansion the IL is
neither fully GIMPLE nor fully RTL.  Given we do not perform many
range queries we might be just lucky to not run into any issues?

Can we maybe try forcing a range query for all SSA names we expand
to increase coverage?  I'll also note that

  get_global_range_query ()->range_of_expr (arg1, arg2)

does not use any context, but only context for defs when querying up
the chain.  Context should generally be the current stmt we expand,
we could set a global 'curr_gimple_stmt_expanded' in expand_gimple_stmt
(where we also set input_location).

That said, I'd be a little less nervous if we'd process basic-blocks
in dominator order instead of in the way we do now.  IIRC we do not
create new basic-blocks up to the first expand_gimple_basic_block?
So using, say, get_all_dominated_blocks (we free dominators, possibly
PHI expansion might insert on edges) to get a PRE ordered set of
blocks to visit, just to make it less random.

Richard.

> I havent tried the relation oracle in a situation such as this when the CFG is
> in flux, but worst case is you just dont create one.  Similarly the inferred
> range oracle is untested in such circumstance, but as long as the CFG is
> rational, they should all work.  I think they just use the dominator structure
> anyway.
> 
> anyway, there is currently no direct way to enable a dom_ranger, you'd have to
> do it the same way fast_vrp does...  its not onerous, just needs a little
> manual tweaking. look at tree-vrp.cc::execute_fast_vrp.
> 
> the important bits are:
> 
> 
>   dom_ranger dr;
> 
>   gcc_checking_assert (!fun->x_range_query);
>   fun->x_range_query = &dr;
>   // Create a relation oracle without transitives if you want an oracle
>   get_range_query (fun)->create_relation_oracle (false);
>   <....>
>   get_range_query (fun)->destroy_relation_oracle ();
>   fun->x_range_query = NULL;
> 
> 
> As long as all queries come in dominator order, it should work just fine as an
> option.
> 
> Andrew
> 
> On 6/6/25 09:33, Jakub Jelinek wrote:
> > Hi!
> >
> > As the following testcase shows, during expansion we use value range info
> > in lots of places, but sadly currently use only the global ranges.
> > It is mostly through get_range_pos_neg function, which uses
> > get_global_range_query ()->range_of_expr (arg1, arg2)
> > but other spots use it directly.
> >
> > On the testcase at the end of the patch, in foo we don't know range of x,
> > so emit the at least on x86_64 less efficient signed division in that case.
> > In bar, the default def SSA_NAME has global range and we try to expand
> > the division both as signed and unsigned because the range proves they will
> > have the same result and choose the cheaper one.
> > And finally in baz, we have VARYING in global range, but can do better if
> > we ask for range at the statement we're expanding.
> >
> > The main problem of using the ranger during expansion is that things are in
> > flux, the already expanded basic blocks switch their IL from gimple to RTL
> > (bb->flags & BB_RTL) and the gimple stmts are gone, PHI nodes even earlier,
> > etc.
> >
> > The patch attempts to make the ranger usable by keeping (bb->flags & BB_RTL)
> > == 0 on basic blocks for longer, in particular until the last
> > expand_gimple_basic_block call for the function.  Instead of changing the
> > IL right away, it uses a vector indexed by bb->index to hold the
> > future BB_HEAD/BB_END.  I had to do a few changes on the ranger side and
> > maybe testing in the wild will show a few extra cases, but I think those
> > are tolerable and can be guarded with currently_expanding_to_rtl so that
> > we don't punt on consistency checks on normal GIMPLE.
> > In particular, even with the patch there will still be some BB_RTL
> > bbs in the IL, e.g. the initial block after ENTRY, ENTRY and EXIT blocks
> > and from time to time others as well, but those should never contain
> > anything intreresting from the ranger POV.  And switch expansion can drop
> > the default edge if it is __builtin_unreachable.
> >
> > Also, had to change the internal call TER expansion, the current way
> > of temporarily changing gimple_call_lhs ICEd badly in the ranger, so I'm
> > instead temporarily changing SSA_NAME_VAR of the SSA_NAME.
> >
> > Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
> >
> > 2025-06-06  Jakub Jelinek  <ja...@redhat.com>
> >
> >  PR middle-end/120434
> >  * cfgrtl.h (update_bb_for_insn_chain): Declare.
> >  * cfgrtl.cc (update_bb_for_insn_chain): No longer static.
> >  * cfgexpand.cc: Include "gimple-range.h".
> >  (head_end_for_bb): New variable.
> >  (label_rtx_for_bb): Drop ATTRIBUTE_UNUSED from bb argument.
> >  Use head_end_for_bb if possible for non-BB_RTL bbs.
> >  (expand_gimple_cond): Don't clear EDGE_TRUE_VALUE and
> >  EDGE_FALSE_VALUE just yet.  Use head_end_for_bb elts instead
> >  of BB_END and update_bb_for_insn_chain instead of update_bb_for_insn.
> >  (expand_gimple_tailcall): Use head_end_for_bb elts instead
> >  of BB_END and update_bb_for_insn_chain instead of update_bb_for_insn.
> >  (expand_gimple_basic_block): Don't change bb to BB_RTL here, instead
> >  use head_end_for_bb elts instead of BB_HEAD and BB_END.  Use
> >  update_bb_for_insn_chain instead of update_bb_for_insn.
> >  (pass_expand::execute): Enable ranger before expand_gimple_basic_block
> >  calls and create head_end_for_bb vector.  Disable ranger after
> >  those calls, turn still non-BB_RTL blocks into BB_RTL and set their
> >  BB_HEAD and BB_END from head_end_for_bb elts, and clear EDGE_TRUE_VALUE
> >  and EDGE_FALSE_VALUE flags on edges.  Release head_end_for_bb
> >  vector.
> >  * tree-outof-ssa.cc (expand_phi_nodes): Don't clear phi nodes here.
> >  * tree.h (get_range_pos_neg): Add gimple * argument defaulted to NULL.
> >  * tree.cc (get_range_pos_neg): Add stmt argument.  Use
> >  get_range_query (cfun) instead of get_global_range_query () and pass
> >  stmt as third argument to range_of_expr.
> >  * expr.cc (expand_expr_divmod): Pass currently_expanding_gimple_stmt
> >  to get_range_pos_neg.
> >  (expand_expr_real_1) <case SSA_NAME>: Change internal fn handling
> >  to avoid temporarily overwriting gimple_call_lhs of ifn, instead
> >  temporarily overwrite SSA_NAME_VAR of its lhs.
> >  (maybe_optimize_pow2p_mod_cmp): Pass currently_expanding_gimple_stmt
> >  to get_range_pos_neg.
> >  (maybe_optimize_mod_cmp): Likewise.
> >  * internal-fn.cc (get_min_precision): Likewise.  Use
> >  get_range_query (cfun) instead of get_global_range_query () and pass
> >  currently_expanding_gimple_stmt as third argument to range_of_expr.
> >  Pass g to get_range_pos_neg.
> >  (expand_addsub_overflow): Pass currently_expanding_gimple_stmt
> >  to get_range_pos_neg.
> >  (expand_mul_overflow): Likewise.
> >  (expand_arith_overflow): Pass stmt to get_range_pos_neg.
> >  * gimple-range-edge.cc: Include rtl.h.
> >  (gimple_outgoing_range_stmt_p): Return NULL for BB_RTL bbs.
> >  (gimple_outgoing_range::calc_switch_range): If default_edge is NULL,
> >  assert currently_expanding_to_rtl and return before trying to
> >  set range on that edge.
> >  * builtins.cc (expand_builtin_strnlen): Use get_range_query (cfun)
> >  instead of get_global_range_query () and pass
> >  currently_expanding_gimple_stmt as third argument to range_of_expr.
> >  (determine_block_size): Likewise.
> >  * gimple-range.cc (gimple_ranger::range_on_exit): Set s to NULL
> >  instead of last_nondebug_stmt for BB_RTL bbs.
> >
> >  * gcc.target/i386/pr120434-1.c: New test.
> >
> > --- gcc/cfgrtl.h.jj 2025-02-13 19:59:55.165577958 +0100
> > +++ gcc/cfgrtl.h    2025-06-05 09:51:24.016105982 +0200
> > @@ -28,6 +28,7 @@ extern basic_block create_basic_block_st
> >   extern void compute_bb_for_insn (void);
> >   extern void free_bb_for_insn (void);
> >   extern rtx_insn *entry_of_function (void);
> > +extern void update_bb_for_insn_chain (rtx_insn *, rtx_insn *, basic_block);
> >   extern void update_bb_for_insn (basic_block);
> >   extern bool contains_no_active_insn_p (const_basic_block);
> >   extern bool forwarder_block_p (const_basic_block);
> > --- gcc/cfgrtl.cc.jj        2025-06-04 21:49:11.975619467 +0200
> > +++ gcc/cfgrtl.cc   2025-06-05 09:50:51.836113156 +0200
> > @@ -538,7 +538,7 @@ emit_insn_at_entry (rtx insn)
> >      The insn chain range is inclusive
> >      (i.e. both BEGIN and END will be updated. */
> >   -static void
> > +void
> >   update_bb_for_insn_chain (rtx_insn *begin, rtx_insn *end, basic_block bb)
> >   {
> >     rtx_insn *insn;
> > --- gcc/cfgexpand.cc.jj     2025-06-04 21:49:11.974619466 +0200
> > +++ gcc/cfgexpand.cc        2025-06-05 11:33:35.022724401 +0200
> > @@ -74,6 +74,7 @@ along with GCC; see the file COPYING3.
> >   #include "output.h"
> >   #include "builtins.h"
> >   #include "opts.h"
> > +#include "gimple-range.h"
> >   
> >   /* Some systems use __main in a way incompatible with its use in gcc, in
> >   these
> >      cases use the macros NAME__MAIN to give a quoted symbol and
> > SYMBOL__MAIN to
> > @@ -2771,6 +2772,10 @@ maybe_dump_rtl_for_gimple_stmt (gimple *
> >       }
> >   }
> >   
> > +/* Temporary storage for BB_HEAD and BB_END of bbs until they are converted
> > +   to BB_RTL.  */
> > +static vec<std::pair <rtx_insn *, rtx_insn *>> head_end_for_bb;
> > +
> >   /* Maps the blocks that do not contain tree labels to rtx labels.  */
> >   
> >   static hash_map<basic_block, rtx_code_label *> *lab_rtx_for_bb;
> > @@ -2778,11 +2783,23 @@ static hash_map<basic_block, rtx_code_la
> >   /* Returns the label_rtx expression for a label starting basic block BB.
> >   */
> >   
> >   static rtx_code_label *
> > -label_rtx_for_bb (basic_block bb ATTRIBUTE_UNUSED)
> > +label_rtx_for_bb (basic_block bb)
> >   {
> >     if (bb->flags & BB_RTL)
> >       return block_label (bb);
> >   +  if ((unsigned) bb->index < head_end_for_bb.length ()
> > +      && head_end_for_bb[bb->index].first)
> > +    {
> > +      if (!LABEL_P (head_end_for_bb[bb->index].first))
> > +   {
> > +     head_end_for_bb[bb->index].first
> > +       = emit_label_before (gen_label_rtx (),
> > +                            head_end_for_bb[bb->index].first);
> > +   }
> > +      return as_a <rtx_code_label *> (head_end_for_bb[bb->index].first);
> > +    }
> > +
> >     rtx_code_label **elt = lab_rtx_for_bb->get (bb);
> >     if (elt)
> >       return *elt;
> > @@ -2942,10 +2959,6 @@ expand_gimple_cond (basic_block bb, gcon
> >     extract_true_false_edges_from_block (bb, &true_edge, &false_edge);
> >     set_curr_insn_location (gimple_location (stmt));
> >   -  /* These flags have no purpose in RTL land.  */
> > -  true_edge->flags &= ~EDGE_TRUE_VALUE;
> > -  false_edge->flags &= ~EDGE_FALSE_VALUE;
> > -
> >     /* We can either have a pure conditional jump with one fallthru edge or
> >        two-way jump that needs to be decomposed into two basic blocks.  */
> >     if (false_edge->dest == bb->next_bb)
> > @@ -2978,10 +2991,12 @@ expand_gimple_cond (basic_block bb, gcon
> >       set_curr_insn_location (false_edge->goto_locus);
> >     emit_jump (label_rtx_for_bb (false_edge->dest));
> >   -  BB_END (bb) = last;
> > -  if (BARRIER_P (BB_END (bb)))
> > -    BB_END (bb) = PREV_INSN (BB_END (bb));
> > -  update_bb_for_insn (bb);
> > +  head_end_for_bb[bb->index].second = last;
> > +  if (BARRIER_P (head_end_for_bb[bb->index].second))
> > +    head_end_for_bb[bb->index].second
> > +      = PREV_INSN (head_end_for_bb[bb->index].second);
> > +  update_bb_for_insn_chain (head_end_for_bb[bb->index].first,
> > +                       head_end_for_bb[bb->index].second, bb);
> >   
> >     new_bb = create_basic_block (NEXT_INSN (last), get_last_insn (), bb);
> >     dest = false_edge->dest;
> > @@ -4473,8 +4488,9 @@ expand_gimple_tailcall (basic_block bb,
> >     e = make_edge (bb, EXIT_BLOCK_PTR_FOR_FN (cfun), EDGE_ABNORMAL
> >      | EDGE_SIBCALL);
> >     e->probability = probability;
> > -  BB_END (bb) = last;
> > -  update_bb_for_insn (bb);
> > +  head_end_for_bb[bb->index].second = last;
> > +  update_bb_for_insn_chain (head_end_for_bb[bb->index].first,
> > +                       head_end_for_bb[bb->index].second, bb);
> >   
> >     if (NEXT_INSN (last))
> >       {
> > @@ -6092,7 +6108,6 @@ static basic_block
> >   expand_gimple_basic_block (basic_block bb, bool disable_tail_calls)
> >   {
> >     gimple_stmt_iterator gsi;
> > -  gimple_seq stmts;
> >     gimple *stmt = NULL;
> >     rtx_note *note = NULL;
> >     rtx_insn *last;
> > @@ -6110,18 +6125,12 @@ expand_gimple_basic_block (basic_block b
> >        access the BB sequence directly.  */
> >     if (optimize)
> >       reorder_operands (bb);
> > -  stmts = bb_seq (bb);
> > -  bb->il.gimple.seq = NULL;
> > -  bb->il.gimple.phi_nodes = NULL;
> >     rtl_profile_for_bb (bb);
> > -  init_rtl_bb_info (bb);
> > -  bb->flags |= BB_RTL;
> >   
> >     /* Remove the RETURN_EXPR if we may fall though to the exit
> >        instead.  */
> > -  gsi = gsi_last (stmts);
> > -  if (!gsi_end_p (gsi)
> > -      && gimple_code (gsi_stmt (gsi)) == GIMPLE_RETURN)
> > +  gsi = gsi_last_bb (bb);
> > +  if (!gsi_end_p (gsi) && gimple_code (gsi_stmt (gsi)) == GIMPLE_RETURN)
> >       {
> >         greturn *ret_stmt = as_a <greturn *> (gsi_stmt (gsi));
> >   @@ -6136,7 +6145,7 @@ expand_gimple_basic_block (basic_block b
> >    }
> >       }
> >   -  gsi = gsi_start (stmts);
> > +  gsi = gsi_start_bb (bb);
> >     if (!gsi_end_p (gsi))
> >       {
> >         stmt = gsi_stmt (gsi);
> > @@ -6145,6 +6154,8 @@ expand_gimple_basic_block (basic_block b
> >       }
> >   
> >     rtx_code_label **elt = lab_rtx_for_bb->get (bb);
> > +  if ((unsigned) bb->index >= head_end_for_bb.length ())
> > +    head_end_for_bb.safe_grow_cleared (bb->index + 1);
> >   
> >     if (stmt || elt)
> >       {
> > @@ -6160,16 +6171,18 @@ expand_gimple_basic_block (basic_block b
> >          if (elt)
> >    emit_label (*elt);
> >   -      BB_HEAD (bb) = NEXT_INSN (last);
> > -      if (NOTE_P (BB_HEAD (bb)))
> > -   BB_HEAD (bb) = NEXT_INSN (BB_HEAD (bb));
> > -      gcc_assert (LABEL_P (BB_HEAD (bb)));
> > -      note = emit_note_after (NOTE_INSN_BASIC_BLOCK, BB_HEAD (bb));
> > +      head_end_for_bb[bb->index].first = NEXT_INSN (last);
> > +      if (NOTE_P (head_end_for_bb[bb->index].first))
> > +   head_end_for_bb[bb->index].first
> > +     = NEXT_INSN (head_end_for_bb[bb->index].first);
> > +      gcc_assert (LABEL_P (head_end_for_bb[bb->index].first));
> > +      note = emit_note_after (NOTE_INSN_BASIC_BLOCK,
> > +                         head_end_for_bb[bb->index].first);
> >   
> >         maybe_dump_rtl_for_gimple_stmt (stmt, last);
> >       }
> >     else
> > -    BB_HEAD (bb) = note = emit_note (NOTE_INSN_BASIC_BLOCK);
> > +    head_end_for_bb[bb->index].first = note = emit_note
> > (NOTE_INSN_BASIC_BLOCK);
> >   
> >     if (note)
> >       NOTE_BASIC_BLOCK (note) = bb;
> > @@ -6485,9 +6498,10 @@ expand_gimple_basic_block (basic_block b
> >       last = PREV_INSN (PREV_INSN (last));
> >     if (BARRIER_P (last))
> >       last = PREV_INSN (last);
> > -  BB_END (bb) = last;
> > +  head_end_for_bb[bb->index].second = last;
> >   -  update_bb_for_insn (bb);
> > +  update_bb_for_insn_chain (head_end_for_bb[bb->index].first,
> > +                       head_end_for_bb[bb->index].second, bb);
> >   
> >     return bb;
> >   }
> > @@ -7175,10 +7189,35 @@ pass_expand::execute (function *fun)
> >         >= param_max_debug_marker_count)
> >       cfun->debug_nonbind_markers = false;
> >   +  enable_ranger (fun);
> >     lab_rtx_for_bb = new hash_map<basic_block, rtx_code_label *>;
> > +  head_end_for_bb.create (last_basic_block_for_fn (fun));
> >     FOR_BB_BETWEEN (bb, init_block->next_bb, EXIT_BLOCK_PTR_FOR_FN (fun),
> >                       next_bb)
> >       bb = expand_gimple_basic_block (bb, var_ret_seq != NULL_RTX);
> > +  disable_ranger (fun);
> > +  FOR_BB_BETWEEN (bb, init_block->next_bb, EXIT_BLOCK_PTR_FOR_FN (fun),
> > +             next_bb)
> > +    {
> > +      if ((bb->flags & BB_RTL) == 0)
> > +   {
> > +     bb->il.gimple.seq = NULL;
> > +     bb->il.gimple.phi_nodes = NULL;
> > +     init_rtl_bb_info (bb);
> > +     bb->flags |= BB_RTL;
> > +     BB_HEAD (bb) = head_end_for_bb[bb->index].first;
> > +     BB_END (bb) = head_end_for_bb[bb->index].second;
> > +   }
> > +      /* These flags have no purpose in RTL land.  */
> > +      if (EDGE_COUNT (bb->succs) == 2)
> > +   {
> > +     EDGE_SUCC (bb, 0)->flags &= ~(EDGE_TRUE_VALUE | EDGE_FALSE_VALUE);
> > +     EDGE_SUCC (bb, 1)->flags &= ~(EDGE_TRUE_VALUE | EDGE_FALSE_VALUE);
> > +   }
> > +      else if (single_succ_p (bb))
> > +   single_succ_edge (bb)->flags &= ~(EDGE_TRUE_VALUE | EDGE_FALSE_VALUE);
> > +    }
> > +  head_end_for_bb.release ();
> >   
> >     if (MAY_HAVE_DEBUG_BIND_INSNS)
> >       expand_debug_locations ();
> > --- gcc/tree-outof-ssa.cc.jj        2025-06-04 21:49:12.914620947 +0200
> > +++ gcc/tree-outof-ssa.cc   2025-06-05 10:09:48.887964474 +0200
> > @@ -1005,9 +1005,8 @@ get_undefined_value_partitions (var_map
> >   }
> >   
> >   /* Given the out-of-ssa info object SA (with prepared partitions)
> > -   eliminate all phi nodes in all basic blocks.  Afterwards no
> > -   basic block will have phi nodes anymore and there are possibly
> > -   some RTL instructions inserted on edges.  */
> > +   eliminate all phi nodes in all basic blocks.  Afterwards there
> > +   are possibly some RTL instructions inserted on edges.  */
> >   
> >   void
> >   expand_phi_nodes (struct ssaexpand *sa)
> > @@ -1023,7 +1022,6 @@ expand_phi_nodes (struct ssaexpand *sa)
> >    edge_iterator ei;
> >    FOR_EACH_EDGE (e, ei, bb->preds)
> >       eliminate_phi (e, &g);
> > -   set_phi_nodes (bb, NULL);
> >    /* We can't redirect EH edges in RTL land, so we need to do this
> >       here.  Redirection happens only when splitting is necessary,
> >       which it is only for critical edges, normally.  For EH edges
> > --- gcc/tree.h.jj   2025-06-04 21:49:12.940620988 +0200
> > +++ gcc/tree.h      2025-06-05 10:33:37.003056050 +0200
> > @@ -5900,7 +5900,7 @@ extern bool gimple_canonical_types_compa
> >                                              bool trust_type_canonical =
> >   true);
> >   extern bool type_with_interoperable_signedness (const_tree);
> >   extern bitmap get_nonnull_args (const_tree);
> > -extern int get_range_pos_neg (tree);
> > +extern int get_range_pos_neg (tree, gimple * = NULL);
> >   
> >   /* Return true for a valid pair of new and delete operators.  */
> >   extern bool valid_new_delete_pair_p (tree, tree, bool * = NULL);
> > --- gcc/tree.cc.jj  2025-06-04 21:49:12.939620986 +0200
> > +++ gcc/tree.cc     2025-06-05 10:43:55.482120911 +0200
> > @@ -14613,10 +14613,11 @@ verify_type (const_tree t)
> >   
> >   /* Return 1 if ARG interpreted as signed in its precision is known to be
> >      always non-negative or 2 if ARG is known to be always negative, or 3 if
> > -   ARG may be non-negative or negative.  */
> > +   ARG may be non-negative or negative.  STMT if specified is the statement
> > +   on which it is being tested.  */
> >   
> >   int
> > -get_range_pos_neg (tree arg)
> > +get_range_pos_neg (tree arg, gimple *stmt)
> >   {
> >     if (arg == error_mark_node)
> >       return 3;
> > @@ -14649,7 +14650,7 @@ get_range_pos_neg (tree arg)
> >     if (TREE_CODE (arg) != SSA_NAME)
> >       return 3;
> >     int_range_max r;
> > -  while (!get_global_range_query ()->range_of_expr (r, arg)
> > +  while (!get_range_query (cfun)->range_of_expr (r, arg, stmt)
> >     || r.undefined_p () || r.varying_p ())
> >       {
> >         gimple *g = SSA_NAME_DEF_STMT (arg);
> > --- gcc/expr.cc.jj  2025-06-04 21:49:12.159619757 +0200
> > +++ gcc/expr.cc     2025-06-06 10:06:54.923720277 +0200
> > @@ -9687,8 +9687,8 @@ expand_expr_divmod (tree_code code, mach
> >     || code == CEIL_MOD_EXPR || code == ROUND_MOD_EXPR);
> >     if (SCALAR_INT_MODE_P (mode)
> >         && optimize >= 2
> > -      && get_range_pos_neg (treeop0) == 1
> > -      && get_range_pos_neg (treeop1) == 1)
> > +      && get_range_pos_neg (treeop0, currently_expanding_gimple_stmt) == 1
> > +      && get_range_pos_neg (treeop1, currently_expanding_gimple_stmt) == 1)
> >       {
> >           /* If both arguments are known to be positive when interpreted
> >      as signed, we can expand it as both signed and unsigned
> > @@ -11372,11 +11372,16 @@ expand_expr_real_1 (tree exp, rtx target
> >      /* ???  internal call expansion doesn't follow the usual API
> >         of returning the destination RTX and being passed a desired
> >         target.  */
> > +     if (modifier == EXPAND_WRITE)
> > +       return DECL_RTL (SSA_NAME_VAR (exp));
> >      rtx dest = gen_reg_rtx (TYPE_MODE (TREE_TYPE (exp)));
> >      tree tmplhs = make_tree (TREE_TYPE (exp), dest);
> > -     gimple_call_set_lhs (g, tmplhs);
> > +     tree var_or_id = SSA_NAME_VAR (exp);
> > +     if (!var_or_id)
> > +       var_or_id = SSA_NAME_IDENTIFIER (exp);
> > +     SET_SSA_NAME_VAR_OR_IDENTIFIER (exp, tmplhs);
> >       expand_internal_call (as_a <gcall *> (g));
> > -     gimple_call_set_lhs (g, exp);
> > +     SET_SSA_NAME_VAR_OR_IDENTIFIER (exp, var_or_id);
> >      return dest;
> >    }
> >   @@ -13223,7 +13228,7 @@ maybe_optimize_pow2p_mod_cmp (enum tree_
> >         || integer_zerop (*arg1)
> >           /* If c is known to be non-negative, modulo will be expanded as
> >     unsigned
> >      modulo.  */
> > -      || get_range_pos_neg (treeop0) == 1)
> > +      || get_range_pos_neg (treeop0, currently_expanding_gimple_stmt) == 1)
> >       return code;
> >   
> >     /* x % c == d where d < 0 && d <= -c should be always false.  */
> > @@ -13355,7 +13360,8 @@ maybe_optimize_mod_cmp (enum tree_code c
> >     /* If both operands are known to have the sign bit clear, handle
> >        even the signed modulo case as unsigned.  treeop1 is always
> >        positive >= 2, checked above.  */
> > -  if (!TYPE_UNSIGNED (type) && get_range_pos_neg (treeop0) != 1)
> > +  if (!TYPE_UNSIGNED (type)
> > +      && get_range_pos_neg (treeop0, currently_expanding_gimple_stmt) != 1)
> >       sgn = SIGNED;
> >   
> >     if (!TYPE_UNSIGNED (type))
> > --- gcc/internal-fn.cc.jj   2025-06-04 21:49:12.202619825 +0200
> > +++ gcc/internal-fn.cc      2025-06-05 10:44:10.748122613 +0200
> > @@ -926,7 +926,10 @@ get_min_precision (tree arg, signop sign
> >    {
> >      if (TYPE_UNSIGNED (TREE_TYPE (arg)))
> >         sign = UNSIGNED;
> > -     else if (sign == UNSIGNED && get_range_pos_neg (arg) != 1)
> > +     else if (sign == UNSIGNED
> > +              && (get_range_pos_neg (arg,
> > +                                     currently_expanding_gimple_stmt)
> > +                  != 1))
> >        return prec + (orig_sign != sign);
> >      prec = TYPE_PRECISION (TREE_TYPE (arg));
> >     }
> > @@ -946,7 +949,8 @@ get_min_precision (tree arg, signop sign
> >     if (TREE_CODE (arg) != SSA_NAME)
> >       return prec + (orig_sign != sign);
> >     int_range_max r;
> > -  while (!get_global_range_query ()->range_of_expr (r, arg)
> > +  gimple *cg = currently_expanding_gimple_stmt;
> > +  while (!get_range_query (cfun)->range_of_expr (r, arg, cg)
> >     || r.varying_p ()
> >     || r.undefined_p ())
> >       {
> > @@ -963,7 +967,8 @@ get_min_precision (tree arg, signop sign
> >     {
> >       if (TYPE_UNSIGNED (TREE_TYPE (arg)))
> >                 sign = UNSIGNED;
> > -             else if (sign == UNSIGNED && get_range_pos_neg (arg) != 1)
> > +             else if (sign == UNSIGNED
> > +                      && get_range_pos_neg (arg, g) != 1)
> >         return prec + (orig_sign != sign);
> >       prec = TYPE_PRECISION (TREE_TYPE (arg));
> >             }
> > @@ -1301,7 +1306,7 @@ expand_addsub_overflow (location_t loc,
> >     unsigned.  */
> >         res = expand_binop (mode, sub_optab, op0, op1, NULL_RTX, false,
> >                       OPTAB_LIB_WIDEN);
> > -      int pos_neg = get_range_pos_neg (arg0);
> > +      int pos_neg = get_range_pos_neg (arg0,
> > currently_expanding_gimple_stmt);
> >          if (pos_neg == 2)
> >    /* If ARG0 is known to be always negative, this is always overflow.  */
> >    emit_jump (do_error);
> > @@ -1361,10 +1366,11 @@ expand_addsub_overflow (location_t loc,
> >     unsigned.  */
> >         res = expand_binop (mode, code == PLUS_EXPR ? add_optab : sub_optab,
> >                       op0, op1, NULL_RTX, false, OPTAB_LIB_WIDEN);
> > -      int pos_neg = get_range_pos_neg (arg1);
> > +      int pos_neg = get_range_pos_neg (arg1,
> > currently_expanding_gimple_stmt);
> >          if (code == PLUS_EXPR)
> >     {
> > -     int pos_neg0 = get_range_pos_neg (arg0);
> > +     int pos_neg0 = get_range_pos_neg (arg0,
> > +                                       currently_expanding_gimple_stmt);
> >      if (pos_neg0 != 3 && pos_neg == 3)
> >        {
> >           std::swap (op0, op1);
> > @@ -1462,10 +1468,11 @@ expand_addsub_overflow (location_t loc,
> >          the second operand, as subtraction is not commutative) is always
> >          non-negative or always negative, we can do just one comparison
> >          and conditional jump.  */
> > -    int pos_neg = get_range_pos_neg (arg1);
> > +    int pos_neg = get_range_pos_neg (arg1,
> > currently_expanding_gimple_stmt);
> >       if (code == PLUS_EXPR)
> >         {
> > -   int pos_neg0 = get_range_pos_neg (arg0);
> > +   int pos_neg0 = get_range_pos_neg (arg0,
> > +                                     currently_expanding_gimple_stmt);
> >    if (pos_neg0 != 3 && pos_neg == 3)
> >      {
> >         std::swap (op0, op1);
> > @@ -1757,8 +1764,8 @@ expand_mul_overflow (location_t loc, tre
> >         uns1_p = true;
> >       }
> >   -  int pos_neg0 = get_range_pos_neg (arg0);
> > -  int pos_neg1 = get_range_pos_neg (arg1);
> > +  int pos_neg0 = get_range_pos_neg (arg0, currently_expanding_gimple_stmt);
> > +  int pos_neg1 = get_range_pos_neg (arg1, currently_expanding_gimple_stmt);
> >     /* Unsigned types with smaller than mode precision, even if they have
> >     most
> >        significant bit set, are still zero-extended.  */
> >     if (uns0_p && TYPE_PRECISION (TREE_TYPE (arg0)) < GET_MODE_PRECISION
> > (mode))
> > @@ -2763,9 +2770,9 @@ expand_arith_overflow (enum tree_code co
> >     int prec1 = TYPE_PRECISION (TREE_TYPE (arg1));
> >     int precres = TYPE_PRECISION (type);
> >     location_t loc = gimple_location (stmt);
> > -  if (!uns0_p && get_range_pos_neg (arg0) == 1)
> > +  if (!uns0_p && get_range_pos_neg (arg0, stmt) == 1)
> >       uns0_p = true;
> > -  if (!uns1_p && get_range_pos_neg (arg1) == 1)
> > +  if (!uns1_p && get_range_pos_neg (arg1, stmt) == 1)
> >       uns1_p = true;
> >     int pr = get_min_precision (arg0, uns0_p ? UNSIGNED : SIGNED);
> >     prec0 = MIN (prec0, pr);
> > --- gcc/gimple-range-edge.cc.jj     2025-01-02 20:54:32.235128454 +0100
> > +++ gcc/gimple-range-edge.cc        2025-06-06 10:07:59.319876245 +0200
> > @@ -32,6 +32,7 @@ along with GCC; see the file COPYING3.
> >   #include "tree-cfg.h"
> >   #include "gimple-range.h"
> >   #include "value-range-storage.h"
> > +#include "rtl.h"
> >   
> >   // If there is a range control statement at the end of block BB, return
> >   it.
> >   // Otherwise return NULL.
> > @@ -39,6 +40,8 @@ along with GCC; see the file COPYING3.
> >   gimple *
> >   gimple_outgoing_range_stmt_p (basic_block bb)
> >   {
> > +  if (bb->flags & BB_RTL)
> > +    return NULL;
> >     gimple_stmt_iterator gsi = gsi_last_nondebug_bb (bb);
> >     if (!gsi_end_p (gsi))
> >       {
> > @@ -190,6 +193,14 @@ gimple_outgoing_range::calc_switch_range
> >         slot = m_range_allocator->clone (case_range);
> >       }
> >   +  if (default_edge == NULL)
> > +    {
> > +      /* During expansion the default edge could have been removed
> > +    if the default is unreachable.  */
> > +      gcc_assert (currently_expanding_to_rtl);
> > +      return;
> > +    }
> > +
> >     vrange_storage *&slot = m_edge_table->get_or_insert (default_edge,
> >     &existed);
> >     // This should be the first call into this switch.
> >     gcc_checking_assert (!existed);
> > --- gcc/builtins.cc.jj      2025-06-04 21:49:11.957619439 +0200
> > +++ gcc/builtins.cc 2025-06-05 10:45:51.657133855 +0200
> > @@ -3529,7 +3529,8 @@ expand_builtin_strnlen (tree exp, rtx ta
> >   
> >     wide_int min, max;
> >     int_range_max r;
> > -  get_global_range_query ()->range_of_expr (r, bound);
> > +  get_range_query (cfun)->range_of_expr (r, bound,
> > +                                    currently_expanding_gimple_stmt);
> >     if (r.varying_p () || r.undefined_p ())
> >       return NULL_RTX;
> >     min = r.lower_bound ();
> > @@ -3604,7 +3605,8 @@ determine_block_size (tree len, rtx len_
> >    {
> >      int_range_max r;
> >      tree tmin, tmax;
> > -     get_global_range_query ()->range_of_expr (r, len);
> > +     gimple *cg = currently_expanding_gimple_stmt;
> > +     get_range_query (cfun)->range_of_expr (r, len, cg);
> >      range_type = get_legacy_range (r, tmin, tmax);
> >      if (range_type != VR_UNDEFINED)
> >         {
> > --- gcc/gimple-range.cc.jj  2025-02-13 19:59:55.610575474 +0100
> > +++ gcc/gimple-range.cc     2025-06-05 12:05:45.174074016 +0200
> > @@ -200,7 +200,12 @@ gimple_ranger::range_on_exit (vrange &r,
> >     // If this is not the definition block, get the range on the last stmt
> >     in
> >     // the block... if there is one.
> >     if (def_bb != bb)
> > -    s = last_nondebug_stmt (bb);
> > +    {
> > +      if (bb->flags & BB_RTL)
> > +   s = NULL;
> > +      else
> > +   s = last_nondebug_stmt (bb);
> > +    }
> >     // If there is no statement provided, get the range_on_entry for this
> >     block.
> >     if (s)
> >       range_of_expr (r, name, s);
> > --- gcc/testsuite/gcc.target/i386/pr120434-1.c.jj   2025-06-06
> > 11:41:46.881233965 +0200
> > +++ gcc/testsuite/gcc.target/i386/pr120434-1.c      2025-06-06
> > 11:38:26.719692788 +0200
> > @@ -0,0 +1,28 @@
> > +/* PR middle-end/120434 */
> > +/* { dg-do compile } */
> > +/* { dg-options "-O2 -mtune=generic -masm=att" } */
> > +/* { dg-final { scan-assembler-times "\tsar\[lq]\t" 2 } } */
> > +/* { dg-final { scan-assembler-times "\tshr\[lq]\t" 2 } } */
> > +
> > +[[gnu::noipa]] int
> > +foo (int x)
> > +{
> > +  return x / 200;
> > +}
> > +
> > +[[gnu::noipa]] int
> > +bar (int x)
> > +{
> > +  if (x < 0)
> > +    __builtin_unreachable ();
> > +  return x / 200;
> > +}
> > +
> > +[[gnu::noipa]] int
> > +baz (int x)
> > +{
> > +  if (x >= 0)
> > +    return x / 200;
> > +  else
> > +    return 24;
> > +}
> >
> >  Jakub
> >
> 
> 

-- 
Richard Biener <rguent...@suse.de>
SUSE Software Solutions Germany GmbH, Frankenstrasse 146, 90461 Nuernberg,
Germany; GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman;
HRB 36809 (AG Nuernberg)

Reply via email to