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

Reply via email to