public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc(refs/users/marxin/heads/loop-unswitching-switch)] Richi's version.
@ 2021-08-31 14:33 Martin Liska
  0 siblings, 0 replies; only message in thread
From: Martin Liska @ 2021-08-31 14:33 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:717b4d8176d645b19ee2d89c5d2d743420c1c759

commit 717b4d8176d645b19ee2d89c5d2d743420c1c759
Author: Martin Liska <mliska@suse.cz>
Date:   Mon Aug 30 15:47:34 2021 +0200

    Richi's version.

Diff:
---
 gcc/tree-ssa-loop-unswitch.c | 86 +++++++++++++++++++++++++++++++++++++-------
 1 file changed, 74 insertions(+), 12 deletions(-)

diff --git a/gcc/tree-ssa-loop-unswitch.c b/gcc/tree-ssa-loop-unswitch.c
index fe4dacc0833..9bfa053bb62 100644
--- a/gcc/tree-ssa-loop-unswitch.c
+++ b/gcc/tree-ssa-loop-unswitch.c
@@ -37,6 +37,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimple-iterator.h"
 #include "cfghooks.h"
 #include "tree-ssa-loop-manip.h"
+#include "cfganal.h"
+#include "tree-cfgcleanup.h"
 
 /* This file implements the loop unswitching, i.e. transformation of loops like
 
@@ -188,17 +190,14 @@ static tree
 tree_may_unswitch_on (basic_block bb, class loop *loop)
 {
   gimple *last, *def;
-  gcond *stmt;
   tree cond, use;
   basic_block def_bb;
   ssa_op_iter iter;
 
   /* BB must end in a simple conditional jump.  */
   last = last_stmt (bb);
-  if (!last || gimple_code (last) != GIMPLE_COND)
-    return NULL_TREE;
-  stmt = as_a <gcond *> (last);
-
+  if (gcond *stmt = safe_dyn_cast <gcond *> (last))
+    {
   /* To keep the things simple, we do not directly remove the conditions,
      but just replace tests with 0 != 0 resp. 1 != 0.  Prevent the infinite
      loop where we would unswitch again on such a condition.  */
@@ -223,6 +222,31 @@ tree_may_unswitch_on (basic_block bb, class loop *loop)
 		 gimple_cond_lhs (stmt), gimple_cond_rhs (stmt));
 
   return cond;
+    }
+  else if (gswitch *stmt = safe_dyn_cast <gswitch *> (last))
+    {
+      tree idx = gimple_switch_index (stmt);
+      if (TREE_CODE (idx) != SSA_NAME
+	  || gimple_switch_num_labels (stmt) < 1)
+	return NULL_TREE;
+      /* Index must be invariant.  */
+      def = SSA_NAME_DEF_STMT (idx);
+      def_bb = gimple_bb (def);
+      if (def_bb
+	  && flow_bb_inside_loop_p (loop, def_bb))
+	return NULL_TREE;
+      /* Unswitching on undefined values would introduce undefined
+	 behavior that the original program might never exercise.  */
+      if (is_maybe_undefined (idx, stmt, loop))
+	return NULL_TREE;
+      /* TODO: pick based on profile or on biggest range (TODO: implement
+	 ranges).  */
+      tree lab = gimple_switch_label (stmt, 1);
+      if (CASE_HIGH (lab))
+	return NULL_TREE;
+      cond = build2 (EQ_EXPR, boolean_type_node, idx, CASE_LOW (lab));
+      return cond;
+    }
 }
 
 /* Simplifies COND using checks in front of the entry of the LOOP.  Just very
@@ -333,22 +357,55 @@ tree_unswitch_single_loop (class loop *loop, int num)
 	  break;
 	}
 
+      // likewise, using copy tables we should be able to "translate"
+      // the unswitched edge instead and adjust the code directly
+      // after the versioning rather than relying on recursion to
+      // fixup the code.
+      tree orig_cond = cond;
       cond = simplify_using_entry_checks (loop, cond);
       stmt = last_stmt (bbs[i]);
       if (integer_nonzerop (cond))
 	{
 	  /* Remove false path.  */
-	  gimple_cond_set_condition_from_tree (as_a <gcond *> (stmt),
-					       boolean_true_node);
+	  if (is_a <gcond  *> (stmt))
+	    gimple_cond_set_condition_from_tree (as_a <gcond *> (stmt),
+						 boolean_true_node);
+	  else
+	    gimple_switch_set_index (as_a <gswitch *> (stmt),
+				     TREE_OPERAND (orig_cond, 1));
 	  changed = true;
 	}
       else if (integer_zerop (cond))
 	{
 	  /* Remove true path.  */
-	  gimple_cond_set_condition_from_tree (as_a <gcond *> (stmt),
-					       boolean_false_node);
+	  if (is_a <gcond  *> (stmt))
+	    gimple_cond_set_condition_from_tree (as_a <gcond *> (stmt),
+						 boolean_false_node);
+	  else
+	    {
+	      start_recording_case_labels ();
+	      // we should know the edge already
+	      gswitch *gs = as_a <gswitch *> (stmt);
+	      tree lab = gimple_switch_label (gs, 1);
+	      basic_block dest = label_to_block (cfun, CASE_LABEL (lab));
+	      edge e = find_edge (gimple_bb (stmt), dest);
+	      // modifying the CFG here may play havoc on things like
+	      // dominators and we really would like to prevent doing
+	      // full update_ssa for each individual unswitching as well
+	      remove_edge (e);
+	      if (gimple_switch_num_labels (gs) > 1)
+		gimple_switch_set_label (gs, 1,
+					 gimple_switch_label (gs, gimple_switch_num_labels (gs) - 1));
+	      gimple_switch_set_num_labels (gs, gimple_switch_num_labels (gs) - 1);
+	      end_recording_case_labels ();
+	      /* Update based on the adjusted switch.  */
+	      cond = tree_may_unswitch_on (bbs[i], loop);
+	    }
 	  changed = true;
 	}
+      // As said, it's a bit hackish to do it this way.  */
+      if (TREE_CODE (cond) == INTEGER_CST)
+	;
       /* Do not unswitch too much.  */
       else if (num > param_max_unswitch_level)
 	{
@@ -459,7 +516,9 @@ tree_unswitch_single_loop (class loop *loop, int num)
     }
 
   /* Update the SSA form after unswitching.  */
-  update_ssa (TODO_update_ssa);
+  free_dominance_info (CDI_DOMINATORS);
+  cleanup_tree_cfg (TODO_update_ssa);
+  //update_ssa (TODO_update_ssa);
   free_original_copy_tables ();
 
   /* Invoke itself on modified loops.  */
@@ -483,10 +542,13 @@ tree_unswitch_loop (class loop *loop,
 
   /* Some sanity checking.  */
   gcc_assert (flow_bb_inside_loop_p (loop, unswitch_on));
-  gcc_assert (EDGE_COUNT (unswitch_on->succs) == 2);
+  //gcc_assert (EDGE_COUNT (unswitch_on->succs) == 2);
   gcc_assert (loop->inner == NULL);
 
-  extract_true_false_edges_from_block (unswitch_on, &edge_true, &edge_false);
+  // TODO: should switch on the edge rather than passing around
+  // a cond tree
+  //extract_true_false_edges_from_block (unswitch_on, &edge_true, &edge_false);
+  edge_true = EDGE_SUCC (unswitch_on, 0);
   prob_true = edge_true->probability;
   return loop_version (loop, unshare_expr (cond),
 		       NULL, prob_true,


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2021-08-31 14:33 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-08-31 14:33 [gcc(refs/users/marxin/heads/loop-unswitching-switch)] Richi's version Martin Liska

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).