https://gcc.gnu.org/g:8154fc95f097a146f9c80edcaafb2baff73065b5

commit r16-1398-g8154fc95f097a146f9c80edcaafb2baff73065b5
Author: Jakub Jelinek <ja...@redhat.com>
Date:   Tue Jun 10 20:04:52 2025 +0200

    expand, ranger: Use ranger during expansion [PR120434]
    
    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.
    
    2025-06-10  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.h (expand_remove_edge): Declare.
            * 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_remove_edge): New function.
            (maybe_cleanup_end_of_block): Use it instead of remove_edge.
            (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 expand_remove_edge instead of
            remove_edge.  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.
            * stmt.cc: Include cfgexpand.h.
            (expand_case): Use expand_remove_edge instead of remove_edge.
    
            * gcc.target/i386/pr120434-1.c: New test.

Diff:
---
 gcc/builtins.cc                            |   6 +-
 gcc/cfgexpand.cc                           | 114 +++++++++++++++++++++--------
 gcc/cfgexpand.h                            |   1 +
 gcc/cfgrtl.cc                              |   2 +-
 gcc/cfgrtl.h                               |   1 +
 gcc/expr.cc                                |  18 +++--
 gcc/gimple-range-edge.cc                   |  11 +++
 gcc/gimple-range.cc                        |   7 +-
 gcc/internal-fn.cc                         |  31 +++++---
 gcc/stmt.cc                                |   3 +-
 gcc/testsuite/gcc.target/i386/pr120434-1.c |  28 +++++++
 gcc/tree-outof-ssa.cc                      |   6 +-
 gcc/tree.cc                                |   7 +-
 gcc/tree.h                                 |   2 +-
 14 files changed, 175 insertions(+), 62 deletions(-)

diff --git a/gcc/builtins.cc b/gcc/builtins.cc
index e818e819f7c8..3064bff1ae63 100644
--- a/gcc/builtins.cc
+++ b/gcc/builtins.cc
@@ -3529,7 +3529,8 @@ expand_builtin_strnlen (tree exp, rtx target, 
machine_mode target_mode)
 
   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_rtx,
        {
          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)
            {
diff --git a/gcc/cfgexpand.cc b/gcc/cfgexpand.cc
index 8919cc33539b..49b0b1404200 100644
--- a/gcc/cfgexpand.cc
+++ b/gcc/cfgexpand.cc
@@ -74,6 +74,7 @@ along with GCC; see the file COPYING3.  If not see
 #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 *stmt, rtx_insn 
*since)
     }
 }
 
+/* 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_label *> 
*lab_rtx_for_bb;
 /* 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;
@@ -2801,6 +2818,19 @@ label_rtx_for_bb (basic_block bb ATTRIBUTE_UNUSED)
 }
 
 
+/* Wrapper around remove_edge during expansion.  */
+
+void
+expand_remove_edge (edge e)
+{
+  if (current_ir_type () != IR_GIMPLE
+      && (e->dest->flags & BB_RTL) == 0
+      && !gimple_seq_empty_p (phi_nodes (e->dest)))
+    remove_phi_args (e);
+  remove_edge (e);
+}
+
+
 /* A subroutine of expand_gimple_cond.  Given E, a fallthrough edge
    of a basic block where we just expanded the conditional at the end,
    possibly clean up the CFG and instruction sequence.  LAST is the
@@ -2823,7 +2853,7 @@ maybe_cleanup_end_of_block (edge e, rtx_insn *last)
   if (BARRIER_P (get_last_insn ()))
     {
       rtx_insn *insn;
-      remove_edge (e);
+      expand_remove_edge (e);
       /* Now, we have a single successor block, if we have insns to
         insert on the remaining edge we potentially will insert
         it at the end of this block (if the dest block isn't feasible)
@@ -2942,10 +2972,6 @@ expand_gimple_cond (basic_block bb, gcond *stmt)
   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 +3004,12 @@ expand_gimple_cond (basic_block bb, gcond *stmt)
     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;
@@ -4445,7 +4473,7 @@ expand_gimple_tailcall (basic_block bb, gcall *stmt, bool 
*can_fallthru)
          if (e->dest != EXIT_BLOCK_PTR_FOR_FN (cfun))
            e->dest->count -= e->count ();
          probability += e->probability;
-         remove_edge (e);
+         expand_remove_edge (e);
        }
       else
        ei_next (&ei);
@@ -4473,8 +4501,9 @@ expand_gimple_tailcall (basic_block bb, gcall *stmt, bool 
*can_fallthru)
   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 +6121,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 +6138,12 @@ expand_gimple_basic_block (basic_block bb, bool 
disable_tail_calls)
      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 +6158,7 @@ expand_gimple_basic_block (basic_block bb, bool 
disable_tail_calls)
        }
     }
 
-  gsi = gsi_start (stmts);
+  gsi = gsi_start_bb (bb);
   if (!gsi_end_p (gsi))
     {
       stmt = gsi_stmt (gsi);
@@ -6145,6 +6167,8 @@ expand_gimple_basic_block (basic_block bb, bool 
disable_tail_calls)
     }
 
   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 +6184,18 @@ expand_gimple_basic_block (basic_block bb, bool 
disable_tail_calls)
       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 +6511,10 @@ expand_gimple_basic_block (basic_block bb, bool 
disable_tail_calls)
     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 +7202,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 ();
diff --git a/gcc/cfgexpand.h b/gcc/cfgexpand.h
index b738059b1858..81ed273a7662 100644
--- a/gcc/cfgexpand.h
+++ b/gcc/cfgexpand.h
@@ -22,6 +22,7 @@ along with GCC; see the file COPYING3.  If not see
 
 extern tree gimple_assign_rhs_to_tree (gimple *);
 extern HOST_WIDE_INT estimated_stack_frame_size (struct cgraph_node *);
+extern void expand_remove_edge (edge);
 extern void set_parm_rtl (tree, rtx);
 
 
diff --git a/gcc/cfgrtl.cc b/gcc/cfgrtl.cc
index 9add2533e743..1b4f78aa4b82 100644
--- a/gcc/cfgrtl.cc
+++ b/gcc/cfgrtl.cc
@@ -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;
diff --git a/gcc/cfgrtl.h b/gcc/cfgrtl.h
index cf12bbb16c06..ab3bb9631a3e 100644
--- a/gcc/cfgrtl.h
+++ b/gcc/cfgrtl.h
@@ -28,6 +28,7 @@ extern basic_block create_basic_block_structure (rtx_insn *, 
rtx_insn *,
 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);
diff --git a/gcc/expr.cc b/gcc/expr.cc
index b3b46a266268..08a58fb5564e 100644
--- a/gcc/expr.cc
+++ b/gcc/expr.cc
@@ -9681,8 +9681,8 @@ expand_expr_divmod (tree_code code, machine_mode mode, 
tree treeop0,
                || 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
@@ -11366,11 +11366,16 @@ expand_expr_real_1 (tree exp, rtx target, 
machine_mode tmode,
          /* ???  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;
        }
 
@@ -13217,7 +13222,7 @@ maybe_optimize_pow2p_mod_cmp (enum tree_code code, tree 
*arg0, tree *arg1)
       || 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.  */
@@ -13349,7 +13354,8 @@ maybe_optimize_mod_cmp (enum tree_code code, tree 
*arg0, tree *arg1)
   /* 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))
diff --git a/gcc/gimple-range-edge.cc b/gcc/gimple-range-edge.cc
index 99be07e23a75..05491e1dfea9 100644
--- a/gcc/gimple-range-edge.cc
+++ b/gcc/gimple-range-edge.cc
@@ -32,6 +32,7 @@ along with GCC; see the file COPYING3.  If not see
 #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.  If not see
 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_ranges (gswitch *sw)
       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);
diff --git a/gcc/gimple-range.cc b/gcc/gimple-range.cc
index 6b7d4da98008..e91eeb455f1b 100644
--- a/gcc/gimple-range.cc
+++ b/gcc/gimple-range.cc
@@ -200,7 +200,12 @@ gimple_ranger::range_on_exit (vrange &r, basic_block bb, 
tree name)
   // 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);
diff --git a/gcc/internal-fn.cc b/gcc/internal-fn.cc
index 6b04443f7cdd..a0a73fefb906 100644
--- a/gcc/internal-fn.cc
+++ b/gcc/internal-fn.cc
@@ -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, tree_code code, 
tree lhs,
         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, tree_code code, 
tree lhs,
         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, tree_code code, 
tree lhs,
        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, tree lhs, tree arg0, 
tree arg1,
       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 code, gimple *stmt)
   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);
diff --git a/gcc/stmt.cc b/gcc/stmt.cc
index fa0c5d49aa23..a510f8fe9f32 100644
--- a/gcc/stmt.cc
+++ b/gcc/stmt.cc
@@ -52,6 +52,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-cfg.h"
 #include "dumpfile.h"
 #include "builtins.h"
+#include "cfgexpand.h"
 
 
 /* Functions and data structures for expanding case statements.  */
@@ -1025,7 +1026,7 @@ expand_case (gswitch *stmt)
       && gimple_seq_unreachable_p (bb_seq (default_edge->dest)))
     {
       default_label = NULL;
-      remove_edge (default_edge);
+      expand_remove_edge (default_edge);
       default_edge = NULL;
     }
 
diff --git a/gcc/testsuite/gcc.target/i386/pr120434-1.c 
b/gcc/testsuite/gcc.target/i386/pr120434-1.c
new file mode 100644
index 000000000000..889b6f420a04
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr120434-1.c
@@ -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;
+}
diff --git a/gcc/tree-outof-ssa.cc b/gcc/tree-outof-ssa.cc
index bdf474dbd936..b71f32028dfe 100644
--- a/gcc/tree-outof-ssa.cc
+++ b/gcc/tree-outof-ssa.cc
@@ -1005,9 +1005,8 @@ get_undefined_value_partitions (var_map 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
diff --git a/gcc/tree.cc b/gcc/tree.cc
index 9759c6b36a6e..c8b8b3edd35a 100644
--- a/gcc/tree.cc
+++ b/gcc/tree.cc
@@ -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);
diff --git a/gcc/tree.h b/gcc/tree.h
index 7e4008e8fb41..c0ecf30d19bb 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -5900,7 +5900,7 @@ extern bool gimple_canonical_types_compatible_p 
(const_tree, const_tree,
                                                 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);

Reply via email to