]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
CRC code generation v2:
authorMariam Arutunian <mariamarutunian@gmail.com>
Fri, 17 Feb 2023 14:00:48 +0000 (18:00 +0400)
committerJeff Law <jlaw@ventanamicro>
Tue, 21 Mar 2023 15:03:21 +0000 (09:03 -0600)
        - Complete expand_crc_optab_fn function.
        - Added RTL generation for CRC (crcqihi4). But yet it doesn't generate the correct sequence.
        - Changed the code for removing the body of CRC function.
        - Added direct_internal_fn_supported_p check before adding the IFN_CRC.

gcc/config/riscv/bitmanip.md
gcc/config/riscv/riscv.md
gcc/gimple-crc-optimization.cc
gcc/internal-fn.cc

index ff9ecb433e4df08cce09184c3ed37071851f4bcb..2419b5a35cf873bd80f675a44e503c3759390e51 100644 (file)
    operands[8] = GEN_INT (setbit);
    operands[9] = GEN_INT (clearbit);
 })
+
+(define_expand "crcqihi4"
+[(set (match_operand:HI 0 "register_operand" "=r")
+(unspec:HI
+[(match_operand:HI 1)
+(match_operand:QI 2)
+(match_operand:HI 3)]
+UNSPEC_CRC16))] ;;
+""
+{
+// FIXME: Note correct instruction sequence.
+rtx data = force_reg (SImode, gen_rtx_ASHIFT (SImode, operands[1],
+                                             GEN_INT (32)));
+
+rtx op3 = simplify_gen_subreg (SImode, operands[3], HImode, 0);
+rtx t2 = force_reg (SImode, gen_rtx_PLUS (SImode, data, op3)); // Must be CLMULH
+
+t2 = force_reg (SImode, gen_rtx_ASHIFT (SImode, t2, GEN_INT (16+1)));
+
+t2 = force_reg (SImode, gen_rtx_LSHIFTRT (SImode, t2, GEN_INT (48-1)));
+
+t2 = force_reg (SImode, gen_rtx_PLUS (SImode, data, t2)); // Must be CLMULH
+
+rtx tgt = simplify_gen_subreg (SImode, operands[0], HImode, 0);
+rtx crc = simplify_gen_subreg (SImode, operands[2], QImode, 0);
+emit_move_insn (tgt, gen_rtx_XOR (SImode, crc, t2));
+DONE;
+})
\ No newline at end of file
index 6c3176042fbd1702a6bb1911a6bf7f093fc5c7a2..f9a62b5f88c8eeb3d5b937be60c8f5bcfd5be7bb 100644 (file)
@@ -65,6 +65,8 @@
 
   ;; OR-COMBINE
   UNSPEC_ORC_B
+
+  UNSPEC_CRC16
 ])
 
 (define_c_enum "unspecv" [
index bfd9562ff84645ac3446665a8eac9e55ceae4c36..48bd0efee160d27ed03a3635e9a8afefe433c815 100644 (file)
@@ -205,7 +205,7 @@ class crc_optimization {
 
   /* Replaces function body with CRC_IFN call.
    Returns true if replacement is succeeded, otherwise false.  */
-  bool faster_crc_code_generation (function *);
+  bool faster_crc_code_generation (function *fun);
 
  public:
   unsigned int execute (function *fun);
@@ -1011,209 +1011,70 @@ crc_optimization::function_may_calculate_crc (function *fun)
 /* Remove all statements and basic blocks of the function
    except for the return statement.  */
 gimple *
-remove_stmts_besides_return (function *fun)
+remove_stmts_besides_return (function *fun, class loop *crc_loop)
 {
   gimple_stmt_iterator gsi;
   basic_block bb, next_bb;
   gimple *return_stmt = NULL;
+  cancel_loop_tree (crc_loop);
   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);)
+      for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
        {
          gimple *gs = gsi_stmt (gsi);
+         // TODO: Check whether it's better to get return
+         //  statement during symbolic execution step and change.
          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);
+           return_stmt = gs;
        }
 
-      for (ei = ei_start (bb->succs); (e = ei_safe_edge (ei));)
-       {
-         e->src = bb->prev_bb;
-         remove_edge (e);
-       }*/
-
+      next_bb = bb->next_bb;
+      // TODO: what if return statement's block isn't the last one?!
       if (!return_stmt)
+       delete_basic_block (bb);
+      else
        {
-         next_bb = bb->next_bb;
-         delete_basic_block (bb);
+         // TODO: Check whether there can be other statements
+         // besides return in the block.  Delete them if any.
+         /* Delete phi statements of the return block.  */
+         for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi);)
+           gsi_remove (&gsi, true);
        }
-      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;
+   return false;
+  // TODO: Use another way of figuring out which argument is data, as this won't
+  // work correctly in case when data is xor-ed with crc before the loop.
   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);
+  if (!direct_internal_fn_supported_p
+      (IFN_CRC, tree_pair (TREE_TYPE (data_arg), TREE_TYPE (crc_arg)),
+       OPTIMIZE_FOR_BOTH))
+  {
+    if (dump_file)
+      fprintf (dump_file, "No matching optab entry\n");
+    return false;
+  }
+
+  gimple *return_stmt = remove_stmts_besides_return (fun, crc_loop);
 
   /* Add IFN call and return the value.  */
   gcall *call
       = gimple_build_call_internal (IFN_CRC, 3,
                                    crc_arg,
                                    data_arg,
-                                   data_arg);
+                                   crc_arg); // must be changed to polynomial
 
   tree result = make_ssa_name (TREE_TYPE (DECL_RESULT (fun->decl)));
   gimple_call_set_lhs (call, result);
index 140ac255289f7be0a0ce21b1ceb107d5080cd693..90db7aedaf23acbb8aa5ee1480aae1de4ffc3703 100644 (file)
@@ -3720,9 +3720,27 @@ 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);
+    tree rhs1 = gimple_call_arg (stmt, 0); // crc
+    tree rhs2 = gimple_call_arg (stmt, 1); // data
+    tree rhs3 = gimple_call_arg (stmt, 2); // polynomial
+    tree result_type = TREE_TYPE (lhs);
+    tree data_type = TREE_TYPE (rhs2);
+
+    rtx dest = expand_expr (lhs, NULL_RTX, SImode, EXPAND_WRITE);
+    rtx op1 = expand_normal (rhs1);
+    rtx op2 = expand_normal (rhs2);
+    rtx op3 = expand_normal (rhs3);
+
+    class expand_operand ops[4];
+    create_output_operand (&ops[0], dest, TYPE_MODE (result_type));
+    create_input_operand (&ops[1], op1, TYPE_MODE (result_type)); // crc
+    create_input_operand (&ops[2], op2, TYPE_MODE (data_type)); // data
+    create_input_operand (&ops[3], op3, TYPE_MODE (result_type)); //polynom
+    insn_code icode = convert_optab_handler (optab, TYPE_MODE (data_type),
+                                            TYPE_MODE (result_type));
+    expand_insn (icode, 4, ops);
+    if (!rtx_equal_p (dest, ops[0].value))
+      emit_move_insn (dest, ops[0].value);
 }
 
 /* Expanders for optabs that can use expand_direct_optab_fn.  */