ccmp.c (ccmp_tree_comparison_p): New function.
authorSteve Ellcey <sellcey@cavium.com>
Thu, 29 Jun 2017 18:20:14 +0000 (18:20 +0000)
committerSteve Ellcey <sje@gcc.gnu.org>
Thu, 29 Jun 2017 18:20:14 +0000 (18:20 +0000)
2017-06-29  Steve Ellcey  <sellcey@cavium.com>

* ccmp.c (ccmp_tree_comparison_p): New function.
(ccmp_candidate_p): Update to use above function.
(get_compare_parts): New function.
(expand_ccmp_next): Update to use new functions.
(expand_ccmp_expr_1): Take tree arg instead of gimple, update to use
new functions.
(expand_ccmp_expr): Pass tree instead of gimple to expand_ccmp_expr_1,
take mode as argument.
* ccmp.h (expand_ccmp_expr): Add mode as argument.
* expr.c (expand_expr_real_1): Pass mode as argument.

From-SVN: r249805

gcc/ChangeLog
gcc/ccmp.c
gcc/ccmp.h
gcc/expr.c

index dac1d7af9a06d0cb3d0ae93bb03d2c9e7819b531..079c674a7ce674b22b44a01178ddd6332cea32f1 100644 (file)
@@ -1,3 +1,16 @@
+2017-06-29  Steve Ellcey  <sellcey@cavium.com>
+
+       * ccmp.c (ccmp_tree_comparison_p): New function.
+       (ccmp_candidate_p): Update to use above function.
+       (get_compare_parts): New function.
+       (expand_ccmp_next): Update to use new functions.
+       (expand_ccmp_expr_1): Take tree arg instead of gimple, update to use
+       new functions.
+       (expand_ccmp_expr): Pass tree instead of gimple to expand_ccmp_expr_1,
+       take mode as argument.
+       * ccmp.h (expand_ccmp_expr): Add mode as argument.
+       * expr.c (expand_expr_real_1): Pass mode as argument.
+
 2017-06-29  Segher Boessenkool  <segher@kernel.crashing.org>
 
        * combine.c (combine_instructions): Print insns to dump_file, together
index 92ca133d842156374986e4585b1a0151c821b2a3..4fa3ebdc422b6e877532e030ed7d2169ab45f4e1 100644 (file)
@@ -38,6 +38,29 @@ along with GCC; see the file COPYING3.  If not see
 #include "ccmp.h"
 #include "predict.h"
 
+/* Check whether T is a simple boolean variable or a SSA name
+   set by a comparison operator in the same basic block.  */
+static bool
+ccmp_tree_comparison_p (tree t, basic_block bb)
+{
+  gimple *g = get_gimple_for_ssa_name (t);
+  tree_code tcode;
+
+  /* If we have a boolean variable allow it and generate a compare
+     to zero reg when expanding.  */
+  if (!g)
+    return (TREE_CODE (TREE_TYPE (t)) == BOOLEAN_TYPE);
+
+  /* Check to see if SSA name is set by a comparison operator in
+     the same basic block.  */ 
+  if (!is_gimple_assign (g))
+    return false;
+  if (bb != gimple_bb (g))
+    return false;
+  tcode = gimple_assign_rhs_code (g);
+  return TREE_CODE_CLASS (tcode) == tcc_comparison;
+}
+
 /* The following functions expand conditional compare (CCMP) instructions.
    Here is a short description about the over all algorithm:
      * ccmp_candidate_p is used to identify the CCMP candidate
@@ -71,49 +94,69 @@ along with GCC; see the file COPYING3.  If not see
 static bool
 ccmp_candidate_p (gimple *g)
 {
-  tree rhs = gimple_assign_rhs_to_tree (g);
+  tree rhs;
   tree lhs, op0, op1;
   gimple *gs0, *gs1;
-  tree_code tcode, tcode0, tcode1;
-  tcode = TREE_CODE (rhs);
+  tree_code tcode;
+  basic_block bb;
+
+  if (!g)
+    return false;
 
+  rhs = gimple_assign_rhs_to_tree (g);
+  tcode = TREE_CODE (rhs);
   if (tcode != BIT_AND_EXPR && tcode != BIT_IOR_EXPR)
     return false;
 
   lhs = gimple_assign_lhs (g);
   op0 = TREE_OPERAND (rhs, 0);
   op1 = TREE_OPERAND (rhs, 1);
+  bb = gimple_bb (g);
 
   if ((TREE_CODE (op0) != SSA_NAME) || (TREE_CODE (op1) != SSA_NAME)
       || !has_single_use (lhs))
     return false;
 
-  gs0 = get_gimple_for_ssa_name (op0);
-  gs1 = get_gimple_for_ssa_name (op1);
-  if (!gs0 || !gs1 || !is_gimple_assign (gs0) || !is_gimple_assign (gs1)
-      /* g, gs0 and gs1 must be in the same basic block, since current stage
-        is out-of-ssa.  We can not guarantee the correctness when forwording
-        the gs0 and gs1 into g whithout DATAFLOW analysis.  */
-      || gimple_bb (gs0) != gimple_bb (gs1)
-      || gimple_bb (gs0) != gimple_bb (g))
-    return false;
+  gs0 = get_gimple_for_ssa_name (op0); /* gs0 may be NULL */
+  gs1 = get_gimple_for_ssa_name (op1); /* gs1 may be NULL */
 
-  tcode0 = gimple_assign_rhs_code (gs0);
-  tcode1 = gimple_assign_rhs_code (gs1);
-  if (TREE_CODE_CLASS (tcode0) == tcc_comparison
-      && TREE_CODE_CLASS (tcode1) == tcc_comparison)
+  if (ccmp_tree_comparison_p (op0, bb) && ccmp_tree_comparison_p (op1, bb))
     return true;
-  if (TREE_CODE_CLASS (tcode0) == tcc_comparison
-      && ccmp_candidate_p (gs1))
+  if (ccmp_tree_comparison_p (op0, bb) && ccmp_candidate_p (gs1))
     return true;
-  else if (TREE_CODE_CLASS (tcode1) == tcc_comparison
-          && ccmp_candidate_p (gs0))
+  if (ccmp_tree_comparison_p (op1, bb) && ccmp_candidate_p (gs0))
     return true;
   /* We skip ccmp_candidate_p (gs1) && ccmp_candidate_p (gs0) since
-     there is no way to set the CC flag.  */
+     there is no way to set and maintain the CC flag on both sides of
+     the logical operator at the same time.  */
   return false;
 }
 
+/* Extract the comparison we want to do from the tree.  */
+void
+get_compare_parts (tree t, int *up, rtx_code *rcode,
+                  tree *rhs1, tree *rhs2)
+{
+  tree_code code;
+  gimple *g = get_gimple_for_ssa_name (t);
+  if (g)
+    {
+      *up = TYPE_UNSIGNED (TREE_TYPE (gimple_assign_rhs1 (g)));
+      code = gimple_assign_rhs_code (g);
+      *rcode = get_rtx_code (code, *up);
+      *rhs1 = gimple_assign_rhs1 (g);
+      *rhs2 = gimple_assign_rhs2 (g);
+    }
+  else
+    {
+      /* If g is not a comparison operator create a compare to zero.  */
+      *up = 1;
+      *rcode = NE;
+      *rhs1 = t;
+      *rhs2 = build_zero_cst (TREE_TYPE (t));
+    }
+}
+
 /* PREV is a comparison with the CC register which represents the
    result of the previous CMP or CCMP.  The function expands the
    next compare based on G which is ANDed/ORed with the previous
@@ -121,20 +164,16 @@ ccmp_candidate_p (gimple *g)
    PREP_SEQ returns all insns to prepare opearands for compare.
    GEN_SEQ returns all compare insns.  */
 static rtx
-expand_ccmp_next (gimple *g, tree_code code, rtx prev,
+expand_ccmp_next (tree op, tree_code code, rtx prev,
                  rtx_insn **prep_seq, rtx_insn **gen_seq)
 {
   rtx_code rcode;
-  int unsignedp = TYPE_UNSIGNED (TREE_TYPE (gimple_assign_rhs1 (g)));
-
-  gcc_assert (code == BIT_AND_EXPR || code == BIT_IOR_EXPR);
-
-  rcode = get_rtx_code (gimple_assign_rhs_code (g), unsignedp);
+  int unsignedp;
+  tree rhs1, rhs2;
 
+  get_compare_parts(op, &unsignedp, &rcode, &rhs1, &rhs2);
   return targetm.gen_ccmp_next (prep_seq, gen_seq, prev, rcode,
-                               gimple_assign_rhs1 (g),
-                               gimple_assign_rhs2 (g),
-                               get_rtx_code (code, 0));
+                               rhs1, rhs2, get_rtx_code (code, 0));
 }
 
 /* Expand conditional compare gimple G.  A typical CCMP sequence is like:
@@ -153,39 +192,42 @@ expand_ccmp_expr_1 (gimple *g, rtx_insn **prep_seq, rtx_insn **gen_seq)
 {
   tree exp = gimple_assign_rhs_to_tree (g);
   tree_code code = TREE_CODE (exp);
-  gimple *gs0 = get_gimple_for_ssa_name (TREE_OPERAND (exp, 0));
-  gimple *gs1 = get_gimple_for_ssa_name (TREE_OPERAND (exp, 1));
+  basic_block bb = gimple_bb (g);
+
+  tree op0 = TREE_OPERAND (exp, 0);
+  tree op1 = TREE_OPERAND (exp, 1);
+  gimple *gs0 = get_gimple_for_ssa_name (op0);
+  gimple *gs1 = get_gimple_for_ssa_name (op1);
   rtx tmp;
-  tree_code code0 = gimple_assign_rhs_code (gs0);
-  tree_code code1 = gimple_assign_rhs_code (gs1);
 
   gcc_assert (code == BIT_AND_EXPR || code == BIT_IOR_EXPR);
-  gcc_assert (gs0 && gs1 && is_gimple_assign (gs0) && is_gimple_assign (gs1));
 
-  if (TREE_CODE_CLASS (code0) == tcc_comparison)
+  if (ccmp_tree_comparison_p (op0, bb))
     {
-      if (TREE_CODE_CLASS (code1) == tcc_comparison)
+      if (ccmp_tree_comparison_p (op1, bb))
        {
          int unsignedp0, unsignedp1;
          rtx_code rcode0, rcode1;
+         tree logical_op0_rhs1, logical_op0_rhs2;
+         tree logical_op1_rhs1, logical_op1_rhs2;
          int speed_p = optimize_insn_for_speed_p ();
+
          rtx tmp2 = NULL_RTX, ret = NULL_RTX, ret2 = NULL_RTX;
          unsigned cost1 = MAX_COST;
          unsigned cost2 = MAX_COST;
 
-         unsignedp0 = TYPE_UNSIGNED (TREE_TYPE (gimple_assign_rhs1 (gs0)));
-         unsignedp1 = TYPE_UNSIGNED (TREE_TYPE (gimple_assign_rhs1 (gs1)));
-         rcode0 = get_rtx_code (code0, unsignedp0);
-         rcode1 = get_rtx_code (code1, unsignedp1);
+         get_compare_parts (op0, &unsignedp0, &rcode0,
+                            &logical_op0_rhs1, &logical_op0_rhs2);
+
+         get_compare_parts (op1, &unsignedp1, &rcode1,
+                            &logical_op1_rhs1, &logical_op1_rhs2);
 
          rtx_insn *prep_seq_1, *gen_seq_1;
          tmp = targetm.gen_ccmp_first (&prep_seq_1, &gen_seq_1, rcode0,
-                                       gimple_assign_rhs1 (gs0),
-                                       gimple_assign_rhs2 (gs0));
-
+                                       logical_op0_rhs1, logical_op0_rhs2);
          if (tmp != NULL)
            {
-             ret = expand_ccmp_next (gs1, code, tmp, &prep_seq_1, &gen_seq_1);
+             ret = expand_ccmp_next (op1, code, tmp, &prep_seq_1, &gen_seq_1);
              cost1 = seq_cost (prep_seq_1, speed_p);
              cost1 += seq_cost (gen_seq_1, speed_p);
            }
@@ -197,27 +239,22 @@ expand_ccmp_expr_1 (gimple *g, rtx_insn **prep_seq, rtx_insn **gen_seq)
          rtx_insn *prep_seq_2, *gen_seq_2;
          if (tmp == NULL || cost1 < COSTS_N_INSNS (25))
            tmp2 = targetm.gen_ccmp_first (&prep_seq_2, &gen_seq_2, rcode1,
-                                          gimple_assign_rhs1 (gs1),
-                                          gimple_assign_rhs2 (gs1));
-
+                                          logical_op1_rhs1, logical_op1_rhs2);
          if (!tmp && !tmp2)
            return NULL_RTX;
-
          if (tmp2 != NULL)
            {
-             ret2 = expand_ccmp_next (gs0, code, tmp2, &prep_seq_2,
+             ret2 = expand_ccmp_next (op0, code, tmp2, &prep_seq_2,
                                       &gen_seq_2);
              cost2 = seq_cost (prep_seq_2, speed_p);
              cost2 += seq_cost (gen_seq_2, speed_p);
            }
-
          if (cost2 < cost1)
            {
              *prep_seq = prep_seq_2;
              *gen_seq = gen_seq_2;
              return ret2;
            }
-
          *prep_seq = prep_seq_1;
          *gen_seq = gen_seq_1;
          return ret;
@@ -227,28 +264,18 @@ expand_ccmp_expr_1 (gimple *g, rtx_insn **prep_seq, rtx_insn **gen_seq)
          tmp = expand_ccmp_expr_1 (gs1, prep_seq, gen_seq);
          if (!tmp)
            return NULL_RTX;
-
-         return expand_ccmp_next (gs0, code, tmp, prep_seq, gen_seq);
+         return expand_ccmp_next (op0, code, tmp, prep_seq, gen_seq);
        }
     }
   else
     {
       gcc_assert (gimple_assign_rhs_code (gs0) == BIT_AND_EXPR
                   || gimple_assign_rhs_code (gs0) == BIT_IOR_EXPR);
-
-      if (TREE_CODE_CLASS (gimple_assign_rhs_code (gs1)) == tcc_comparison)
-       {
-         tmp = expand_ccmp_expr_1 (gs0, prep_seq, gen_seq);
-         if (!tmp)
-           return NULL_RTX;
-
-         return expand_ccmp_next (gs1, code, tmp, prep_seq, gen_seq);
-       }
-      else
-       {
-         gcc_assert (gimple_assign_rhs_code (gs1) == BIT_AND_EXPR
-                     || gimple_assign_rhs_code (gs1) == BIT_IOR_EXPR);
-       }
+      gcc_assert (ccmp_tree_comparison_p (op1, bb));
+      tmp = expand_ccmp_expr_1 (gs0, prep_seq, gen_seq);
+      if (!tmp)
+       return NULL_RTX;
+      return expand_ccmp_next (op1, code, tmp, prep_seq, gen_seq);
     }
 
   return NULL_RTX;
@@ -258,7 +285,7 @@ expand_ccmp_expr_1 (gimple *g, rtx_insn **prep_seq, rtx_insn **gen_seq)
    Return NULL_RTX if G is not a legal candidate or expand fail.
    Otherwise return the target.  */
 rtx
-expand_ccmp_expr (gimple *g)
+expand_ccmp_expr (gimple *g, machine_mode mode)
 {
   rtx_insn *last;
   rtx tmp;
@@ -275,7 +302,6 @@ expand_ccmp_expr (gimple *g)
     {
       insn_code icode;
       machine_mode cc_mode = CCmode;
-      tree lhs = gimple_assign_lhs (g);
       rtx_code cmp_code = GET_CODE (tmp);
 
 #ifdef SELECT_CC_MODE
@@ -284,7 +310,6 @@ expand_ccmp_expr (gimple *g)
       icode = optab_handler (cstore_optab, cc_mode);
       if (icode != CODE_FOR_nothing)
        {
-         machine_mode mode = TYPE_MODE (TREE_TYPE (lhs));
          rtx target = gen_reg_rtx (mode);
 
          emit_insn (prep_seq);
@@ -300,4 +325,3 @@ expand_ccmp_expr (gimple *g)
   delete_insns_since (last);
   return NULL_RTX;
 }
-
index bc1aafbc65ef5f606f9cfc7672d22fae4266534b..93d10491eb9558e1e05e2897545fdc77bf60f013 100644 (file)
@@ -20,6 +20,6 @@ along with GCC; see the file COPYING3.  If not see
 #ifndef GCC_CCMP_H
 #define GCC_CCMP_H
 
-extern rtx expand_ccmp_expr (gimple *);
+extern rtx expand_ccmp_expr (gimple *, machine_mode);
 
 #endif  /* GCC_CCMP_H  */
index 753f5efde6c7eaee14a85b65f9f525ca88138940..0a52a3d7209bcceb705e226d77f13792ce417b01 100644 (file)
@@ -9776,7 +9776,7 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode tmode,
              if (targetm.gen_ccmp_first)
                {
                  gcc_checking_assert (targetm.gen_ccmp_next != NULL);
-                 r = expand_ccmp_expr (g);
+                 r = expand_ccmp_expr (g, mode);
                  if (r)
                    break;
                }