[gcc/devel/jlaw/crc] CRC code generation v1: - Added CRC_IFN, with not complete function body. - Removed basic blocks of

Jeff Law law@gcc.gnu.org
Tue Mar 21 15:09:59 GMT 2023


https://gcc.gnu.org/g:08b8bff52f8945d763ce3af879698633b034c62c

commit 08b8bff52f8945d763ce3af879698633b034c62c
Author: Mariam Arutunian <mariamarutunian@gmail.com>
Date:   Fri Feb 3 17:57:29 2023 +0400

    CRC code generation v1: - Added CRC_IFN, with not complete function body. - Removed basic blocks of the CRC function and added IFN call returning its value.

Diff:
---
 gcc/gimple-crc-optimization.cc | 252 +++++++++++++++++++++++++++++++++++++++++
 gcc/internal-fn.cc             |  11 ++
 gcc/internal-fn.def            |   1 +
 gcc/optabs.def                 |   1 +
 4 files changed, 265 insertions(+)

diff --git a/gcc/gimple-crc-optimization.cc b/gcc/gimple-crc-optimization.cc
index 78400f06318..bfd9562ff84 100644
--- a/gcc/gimple-crc-optimization.cc
+++ b/gcc/gimple-crc-optimization.cc
@@ -35,6 +35,17 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-scalar-evolution.h"
 #include "hwint.h"
 #include "crc_verification.h"
+#include "internal-fn.h"
+#include "tree-into-ssa.h"
+#include "tree-ssa-loop-manip.h"
+#include "predict.h"
+#include "cfghooks.h"
+#include "tree-ssa.h"
+#include "tree-ssa-live.h"
+#include "tree-dfa.h"
+#include "dominance.h"
+#include "tree-ssa-dce.h"
+#include "tree-cfgcleanup.h"
 
 class crc_optimization {
  private:
@@ -192,6 +203,10 @@ class crc_optimization {
   /* Prints extracted details of CRC calculation.  */
   void print_crc_information ();
 
+  /* Replaces function body with CRC_IFN call.
+   Returns true if replacement is succeeded, otherwise false.  */
+  bool faster_crc_code_generation (function *);
+
  public:
   unsigned int execute (function *fun);
 };
@@ -993,6 +1008,238 @@ crc_optimization::function_may_calculate_crc (function *fun)
   return false;
 }
 
+/* Remove all statements and basic blocks of the function
+   except for the return statement.  */
+gimple *
+remove_stmts_besides_return (function *fun)
+{
+  gimple_stmt_iterator gsi;
+  basic_block bb, next_bb;
+  gimple *return_stmt = NULL;
+  for (bb = fun->cfg->x_entry_block_ptr->next_bb;
+       bb != fun->cfg->x_exit_block_ptr; bb = next_bb)
+    {
+
+      for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi);)
+	gsi_remove (&gsi, true);
+
+      for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi);)
+	{
+	  gimple *gs = gsi_stmt (gsi);
+	  if (gimple_code (gs) == GIMPLE_RETURN)
+	    {
+	      return_stmt = gs;
+	      gsi_next (&gsi);
+	    }
+	  else
+	    {
+	      gimple *stmt = gsi_stmt (gsi);
+	      gsi_remove (&gsi, true);
+	      release_defs (stmt);
+	    }
+	}
+/*
+      edge e;
+      edge_iterator ei;
+      for (ei = ei_start (bb->preds); (e = ei_safe_edge (ei));)
+	{
+	  e->dest = bb->next_bb;
+	  remove_edge (e);
+	}
+
+      for (ei = ei_start (bb->succs); (e = ei_safe_edge (ei));)
+	{
+	  e->src = bb->prev_bb;
+	  remove_edge (e);
+	}*/
+
+      if (!return_stmt)
+	{
+	  next_bb = bb->next_bb;
+	  delete_basic_block (bb);
+	}
+      else
+	next_bb = bb->next_bb;
+    }
+  set_immediate_dominator (CDI_DOMINATORS, fun->cfg->x_entry_block_ptr,
+			   return_stmt->bb);
+  make_edge (fun->cfg->x_entry_block_ptr, return_stmt->bb,
+	     EDGE_FALLTHRU);
+  return return_stmt;
+}
+
+void
+remove_statements_and_update_ssa (function *fn)
+{
+  basic_block bb, next_bb;
+  gimple_stmt_iterator gsi;
+
+  for (bb = fn->cfg->x_entry_block_ptr->next_bb;
+       bb != fn->cfg->x_exit_block_ptr; bb = next_bb)
+    {
+      gsi = gsi_last_bb (bb);
+
+      // Remove all statements from the basic block.
+      while (!gsi_end_p (gsi))
+	{
+	  gimple *stmt = gsi_stmt (gsi);
+	  gsi_remove (&gsi, true);
+
+	  // Update the SSA form to remove the dead statement.
+	  release_defs (stmt);
+	}
+
+      // Remove the basic block from the CFG.
+      next_bb = bb->next_bb;
+      delete_basic_block (bb);
+    }
+  remove_unused_locals ();
+  /*set_immediate_dominator (CDI_DOMINATORS, fn->cfg->x_entry_block_ptr,
+			 fn->cfg->x_exit_block_ptr);
+make_edge (fn->cfg->x_entry_block_ptr, EXIT_BLOCK_PTR_FOR_FN (fn),
+	  EDGE_FALLTHRU);*/
+  update_ssa (TODO_update_ssa);
+  free_dominance_info (fn, CDI_DOMINATORS);
+  calculate_dominance_info (CDI_DOMINATORS);
+}
+
+void
+add_return_statement (function *fn)
+{
+  basic_block bb = create_basic_block (NULL, 0, ENTRY_BLOCK_PTR_FOR_FN (fn));
+  gimple_stmt_iterator gsi = gsi_last_bb (bb);
+
+  tree return_value = build_int_cst (integer_type_node, 10);
+  gimple *stmt = gimple_build_return (return_value);
+
+  gsi_insert_after (&gsi, stmt, GSI_NEW_STMT);
+  calculate_dominance_info (CDI_DOMINATORS);
+  // Update the SSA form to reflect the new return statement.
+  update_ssa (TODO_update_ssa);
+
+}
+
+/* Will be removed from here, after writing a correct code.  */
+void
+destroy_loop (class loop *loop)
+{
+  unsigned nbbs = loop->num_nodes;
+  edge exit = single_exit (loop);
+  basic_block src = loop_preheader_edge (loop)->src, dest = exit->dest;
+  basic_block *bbs;
+  unsigned i;
+
+  bbs = get_loop_body_in_dom_order (loop);
+
+  gimple_stmt_iterator dst_gsi = gsi_after_labels (exit->dest);
+  bool safe_p = single_pred_p (exit->dest);
+  for (unsigned i = 0; i < nbbs; ++i)
+    {
+      /* We have made sure to not leave any dangling uses of SSA
+	 names defined in the loop.  With the exception of virtuals.
+	 Make sure we replace all uses of virtual defs that will remain
+	 outside of the loop with the bare symbol as delete_basic_block
+	 will release them.  */
+      for (gphi_iterator gsi = gsi_start_phis (bbs[i]); !gsi_end_p (gsi);
+	   gsi_next (&gsi))
+	{
+	  gphi *phi = gsi.phi ();
+	  if (virtual_operand_p (gimple_phi_result (phi)))
+	    mark_virtual_phi_result_for_renaming (phi);
+	}
+      for (gimple_stmt_iterator gsi = gsi_start_bb (bbs[i]); !gsi_end_p (gsi);)
+	{
+	  gimple *stmt = gsi_stmt (gsi);
+	  tree vdef = gimple_vdef (stmt);
+	  if (vdef && TREE_CODE (vdef) == SSA_NAME)
+	    mark_virtual_operand_for_renaming (vdef);
+	  /* Also move and eventually reset debug stmts.  We can leave
+	     constant values in place in case the stmt dominates the exit.
+	     ???  Non-constant values from the last iteration can be
+	     replaced with final values if we can compute them.  */
+	  if (gimple_debug_bind_p (stmt))
+	    {
+	      tree val = gimple_debug_bind_get_value (stmt);
+	      gsi_move_before (&gsi, &dst_gsi);
+	      if (val
+		  && (!safe_p
+		      || !is_gimple_min_invariant (val)
+		      || !dominated_by_p (CDI_DOMINATORS, exit->src, bbs[i])))
+		{
+		  gimple_debug_bind_reset_value (stmt);
+		  update_stmt (stmt);
+		}
+	    }
+	  else
+	    gsi_next (&gsi);
+	}
+    }
+
+  redirect_edge_pred (exit, src);
+  exit->flags &= ~(EDGE_TRUE_VALUE | EDGE_FALSE_VALUE);
+  exit->flags |= EDGE_FALLTHRU;
+  cancel_loop_tree (loop);
+  rescan_loop_exit (exit, false, true);
+
+  i = nbbs;
+  do
+    {
+      --i;
+      delete_basic_block (bbs[i]);
+    }
+  while (i != 0);
+
+  free (bbs);
+
+  set_immediate_dominator (CDI_DOMINATORS, dest,
+			   recompute_dominator (CDI_DOMINATORS, dest));
+}
+
+/* Replaces function body with CRC_IFN call.
+   Returns true if replacement is succeeded, otherwise false.  */
+bool
+crc_optimization::faster_crc_code_generation (function *fun)
+{
+  if (!(data && first_phi_for_crc))
+    return false;
+  tree crc_arg = PHI_ARG_DEF (first_phi_for_crc, 1);
+  tree data_arg = PHI_ARG_DEF (data, 1);
+  destroy_loop (crc_loop);
+  //repair_loop_structures ();
+  gimple *return_stmt = remove_stmts_besides_return (fun);
+
+  /* Add IFN call and return the value.  */
+  gcall *call
+      = gimple_build_call_internal (IFN_CRC, 3,
+				    crc_arg,
+				    data_arg,
+				    data_arg);
+
+  tree result = make_ssa_name (TREE_TYPE (DECL_RESULT (fun->decl)));
+  gimple_call_set_lhs (call, result);
+  gimple_set_location (call, fun->function_start_locus);
+  gimple_stmt_iterator si = gsi_start_bb (return_stmt->bb);
+  gsi_insert_before (&si, call, GSI_SAME_STMT);
+  use_operand_p imm_use_p;
+  imm_use_iterator iterator;
+  gimple *stmt;
+  FOR_EACH_IMM_USE_STMT (stmt, iterator,
+			 gimple_return_retval (as_a<greturn *> (return_stmt)))
+    {
+      FOR_EACH_IMM_USE_ON_STMT (imm_use_p, iterator)
+	SET_USE (imm_use_p, result);
+      update_stmt (stmt);
+    }
+
+  /* Fix up CFG.  */
+  remove_unused_locals ();
+  scev_reset ();
+  mark_virtual_operands_for_renaming (fun);
+  free_dominance_info (fun, CDI_DOMINATORS);
+  calculate_dominance_info (CDI_DOMINATORS);
+  rewrite_into_loop_closed_ssa (NULL, TODO_update_ssa);
+  return true;
+}
 
 unsigned int
 crc_optimization::execute (function *fun)
@@ -1033,6 +1280,11 @@ crc_optimization::execute (function *fun)
 	  if (dump_file)
 	    fprintf (dump_file, "%s function calculates CRC!\n",
 		     function_name (fun));
+	  if (!faster_crc_code_generation (fun))
+	    {
+	      if (dump_file)
+		fprintf (dump_file, "Couldn't generate faster CRC code.\n");
+	    }
 	}
       else
 	{
diff --git a/gcc/internal-fn.cc b/gcc/internal-fn.cc
index 6e81dc05e0e..140ac255289 100644
--- a/gcc/internal-fn.cc
+++ b/gcc/internal-fn.cc
@@ -131,6 +131,7 @@ init_internal_fns ()
 #define fold_left_direct { 1, 1, false }
 #define mask_fold_left_direct { 1, 1, false }
 #define check_ptrs_direct { 0, 0, false }
+#define crc_direct { 1, -1, true }
 
 const direct_internal_fn_info direct_internal_fn_array[IFN_LAST + 1] = {
 #define DEF_INTERNAL_FN(CODE, FLAGS, FNSPEC) not_direct,
@@ -3715,6 +3716,15 @@ expand_convert_optab_fn (internal_fn fn, gcall *stmt, convert_optab optab,
   expand_fn_using_insn (stmt, icode, 1, nargs);
 }
 
+static void
+expand_crc_optab_fn (internal_fn, gcall *stmt, convert_optab optab)
+{
+    tree lhs = gimple_call_lhs (stmt);
+    tree rhs1 = gimple_call_arg (stmt, 0);
+    tree rhs2 = gimple_call_arg (stmt, 1);
+    tree rhs3 = gimple_call_arg (stmt, 2);
+}
+
 /* Expanders for optabs that can use expand_direct_optab_fn.  */
 
 #define expand_unary_optab_fn(FN, STMT, OPTAB) \
@@ -3830,6 +3840,7 @@ multi_vector_optab_supported_p (convert_optab optab, tree_pair types,
 #define direct_cond_unary_optab_supported_p direct_optab_supported_p
 #define direct_cond_binary_optab_supported_p direct_optab_supported_p
 #define direct_cond_ternary_optab_supported_p direct_optab_supported_p
+#define direct_crc_optab_supported_p convert_optab_supported_p
 #define direct_mask_load_optab_supported_p convert_optab_supported_p
 #define direct_load_lanes_optab_supported_p multi_vector_optab_supported_p
 #define direct_mask_load_lanes_optab_supported_p multi_vector_optab_supported_p
diff --git a/gcc/internal-fn.def b/gcc/internal-fn.def
index 7fe742c2ae7..741bffeb196 100644
--- a/gcc/internal-fn.def
+++ b/gcc/internal-fn.def
@@ -123,6 +123,7 @@ along with GCC; see the file COPYING3.  If not see
   DEF_INTERNAL_OPTAB_FN (NAME, FLAGS, OPTAB, TYPE)
 #endif
 
+DEF_INTERNAL_OPTAB_FN (CRC, ECF_CONST | ECF_NOTHROW, crc, crc)
 DEF_INTERNAL_OPTAB_FN (MASK_LOAD, ECF_PURE, maskload, mask_load)
 DEF_INTERNAL_OPTAB_FN (LOAD_LANES, ECF_CONST, vec_load_lanes, load_lanes)
 DEF_INTERNAL_OPTAB_FN (MASK_LOAD_LANES, ECF_PURE,
diff --git a/gcc/optabs.def b/gcc/optabs.def
index 695f5911b30..849607b6d11 100644
--- a/gcc/optabs.def
+++ b/gcc/optabs.def
@@ -78,6 +78,7 @@ OPTAB_CD(smsub_widen_optab, "msub$b$a4")
 OPTAB_CD(umsub_widen_optab, "umsub$b$a4")
 OPTAB_CD(ssmsub_widen_optab, "ssmsub$b$a4")
 OPTAB_CD(usmsub_widen_optab, "usmsub$a$b4")
+OPTAB_CD(crc_optab, "crc$a$b4")
 OPTAB_CD(vec_load_lanes_optab, "vec_load_lanes$a$b")
 OPTAB_CD(vec_store_lanes_optab, "vec_store_lanes$a$b")
 OPTAB_CD(vec_mask_load_lanes_optab, "vec_mask_load_lanes$a$b")


More information about the Gcc-cvs mailing list