]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
expand, ranger: Use ranger during expansion [PR120434]
authorJakub Jelinek <jakub@redhat.com>
Tue, 10 Jun 2025 18:04:52 +0000 (20:04 +0200)
committerJakub Jelinek <jakub@gcc.gnu.org>
Tue, 10 Jun 2025 18:04:52 +0000 (20:04 +0200)
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  <jakub@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.

14 files changed:
gcc/builtins.cc
gcc/cfgexpand.cc
gcc/cfgexpand.h
gcc/cfgrtl.cc
gcc/cfgrtl.h
gcc/expr.cc
gcc/gimple-range-edge.cc
gcc/gimple-range.cc
gcc/internal-fn.cc
gcc/stmt.cc
gcc/testsuite/gcc.target/i386/pr120434-1.c [new file with mode: 0644]
gcc/tree-outof-ssa.cc
gcc/tree.cc
gcc/tree.h

index e818e819f7c8064050efae4c06e4eefacaf85c31..3064bff1ae6323b9727418fdcfc3a2c5f42fb0d3 100644 (file)
@@ -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)
            {
index 8919cc33539b38a5837ff5fccc31b9b851b481e9..49b0b14042001a01a33f47a904000415acb27309 100644 (file)
@@ -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 ();
index b738059b18583310c987ead65979100b121cc99b..81ed273a76627301a92957942ba2abc84c903155 100644 (file)
@@ -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);
 
 
index 9add2533e743fa5ec0039d9a3a84c29025bb81d3..1b4f78aa4b827b6b3e8ffc4fefbac3081709825f 100644 (file)
@@ -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;
index cf12bbb16c064ac05c1152045ddaed8ee0b782b1..ab3bb9631a3e9440d14f8aacde5e9a8e60ad9c45 100644 (file)
@@ -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);
index b3b46a266268e79567855442eaa8c8e1ce319fe1..08a58fb5564ef7e2558ca79ea3509eed71941666 100644 (file)
@@ -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))
index 99be07e23a7556f06a4ca1a1c4b4d9112a823a94..05491e1dfea9db1abd485457d9cdfe7770b95a1e 100644 (file)
@@ -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);
index 6b7d4da98008de0e28a467d5432640b73ef52c1b..e91eeb455f1b826c2f7f7ee4396db3002aa5f674 100644 (file)
@@ -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);
index 6b04443f7cddf091c7e14736d2d7a971b8a11030..a0a73fefb9067af667e843aef1e5d6de61f893f9 100644 (file)
@@ -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);
index fa0c5d49aa23383025b2c262efb553765af519ae..a510f8fe9f32545d010d00569305a5c7473d914c 100644 (file)
@@ -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"
 
 \f
 /* 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 (file)
index 0000000..889b6f4
--- /dev/null
@@ -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;
+}
index bdf474dbd936bea3254d70b700e7557bfbd1c5a8..b71f32028dfe1b3c859396e68c466d0ccbf1f63e 100644 (file)
@@ -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
index 9759c6b36a6e9a2ad5cf7bb6174263d4397ec9bd..c8b8b3edd35a0ba126bba1f33c7b3103bd299536 100644 (file)
@@ -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);
index 7e4008e8fb411daba34a6f60e2cb6919ea95705e..c0ecf30d19bb2e89e77870dad60f2a0de5ff7fc7 100644 (file)
@@ -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);