re PR target/51244 ([SH] Inefficient conditional branch and code around T bit)
authorOleg Endo <olegendo@gcc.gnu.org>
Wed, 17 Dec 2014 23:08:14 +0000 (23:08 +0000)
committerOleg Endo <olegendo@gcc.gnu.org>
Wed, 17 Dec 2014 23:08:14 +0000 (23:08 +0000)
gcc/
PR target/51244
* config/sh/sh_treg_combine.cc (is_conditional_insn): New function.
(cbranch_trace): Add member rtx* condition_rtx_in_insn, initialize it
accordingly in constructor.
(cbranch_trace::branch_condition_rtx_ref): New function.
(cbranch_trace::branch_condition_rtx): Use branch_condition_rtx_ref.
(sh_treg_combine::try_invert_branch_condition): Invert condition rtx
in insn using reversed_comparison_code and validate_change instead of
invert_jump_1.
(sh_treg_combine::execute): Look for conditional insns in basic blocks
in addition to conditional branches.
* config/sh/sh.md (*movsicc_div0s): Remove combine patterns.

From-SVN: r218850

gcc/ChangeLog
gcc/config/sh/sh.md
gcc/config/sh/sh_treg_combine.cc

index 00b37280adc02ce3866b4fec697c636d3cca39a5..f9e1af53b42df68a2ae7f6d327741703abf01ae4 100644 (file)
@@ -1,3 +1,18 @@
+2014-12-17  Oleg Endo  <olegendo@gcc.gnu.org>
+
+       PR target/51244
+       * config/sh/sh_treg_combine.cc (is_conditional_insn): New function.
+       (cbranch_trace): Add member rtx* condition_rtx_in_insn, initialize it
+       accordingly in constructor.
+       (cbranch_trace::branch_condition_rtx_ref): New function.
+       (cbranch_trace::branch_condition_rtx): Use branch_condition_rtx_ref.
+       (sh_treg_combine::try_invert_branch_condition): Invert condition rtx
+       in insn using reversed_comparison_code and validate_change instead of
+       invert_jump_1.
+       (sh_treg_combine::execute): Look for conditional insns in basic blocks
+       in addition to conditional branches.
+       * config/sh/sh.md (*movsicc_div0s): Remove combine patterns.
+
 2014-12-17  Oleg Endo  <olegendo@gcc.gnu.org>
 
        PR target/51244
index 644dd06a96663066d5123e0e00eb360bbff41927..5aa50a25af9d0c39b8d47b806cd8fd582ff752c6 100644 (file)
                      (label_ref (match_dup 2))
                      (pc)))])
 
-;; Conditional move combine pattern for div0s comparisons.
-;; This is used when TARGET_PRETEND_CMOVE is in effect.
-(define_insn_and_split "*movsicc_div0s"
-  [(set (match_operand:SI 0 "arith_reg_dest" "")
-       (if_then_else:SI (ge (xor:SI (match_operand:SI 1 "arith_reg_operand" "")
-                                    (match_operand:SI 2 "arith_reg_operand" ""))
-                            (const_int 0))
-                        (match_operand:SI 3 "arith_reg_operand" "")
-                        (match_operand:SI 4 "general_movsrc_operand" "")))
-   (clobber (reg:SI T_REG))]
-  "TARGET_PRETEND_CMOVE"
-  "#"
-  "&& 1"
-  [(set (reg:SI T_REG) (lt:SI (xor:SI (match_dup 1) (match_dup 2))
-                             (const_int 0)))
-   (set (match_dup 0)
-       (if_then_else (ne (reg:SI T_REG) (const_int 0))
-                     (match_dup 4)
-                     (match_dup 3)))])
-
-(define_insn_and_split "*movsicc_div0s"
-  [(set (match_operand:SI 0 "arith_reg_dest")
-       (if_then_else:SI (eq (lshiftrt:SI
-                               (match_operand:SI 1 "arith_reg_operand")
-                               (const_int 31))
-                            (lshiftrt:SI
-                               (match_operand:SI 2 "arith_reg_operand")
-                               (const_int 31)))
-                        (match_operand:SI 3 "arith_reg_operand")
-                        (match_operand:SI 4 "general_movsrc_operand")))
-   (clobber (reg:SI T_REG))]
-   "TARGET_PRETEND_CMOVE"
-   "#"
-   "&& 1"
-  [(set (reg:SI T_REG) (lt:SI (xor:SI (match_dup 1) (match_dup 2))
-                             (const_int 0)))
-   (set (match_dup 0)
-       (if_then_else (ne (reg:SI T_REG) (const_int 0))
-                     (match_dup 4)
-                     (match_dup 3)))])
-
 ;; -------------------------------------------------------------------------
 ;; SImode unsigned integer comparisons
 ;; -------------------------------------------------------------------------
index 62392d81f1bfb4b42e1b8a0df8e1b3c2113e8b43..97e677da50c57d6bbdedeb818c06d3adc9888962 100644 (file)
@@ -432,6 +432,16 @@ trace_reg_uses (rtx reg, rtx_insn *start_insn, rtx abort_at_insn)
   return count;
 }
 
+static bool
+is_conditional_insn (rtx_insn* i)
+{
+  if (! (INSN_P (i) && NONDEBUG_INSN_P (i)))
+    return false;
+
+  rtx p = PATTERN (i);
+  return GET_CODE (p) == SET && GET_CODE (XEXP (p, 1)) == IF_THEN_ELSE;
+}
+
 // FIXME: Remove dependency on SH predicate function somehow.
 extern int t_reg_operand (rtx, machine_mode);
 extern int negt_reg_operand (rtx, machine_mode);
@@ -484,6 +494,7 @@ private:
   struct cbranch_trace
   {
     rtx_insn *cbranch_insn;
+    rtx* condition_rtx_in_insn;
     branch_condition_type_t cbranch_type;
 
     // The comparison against zero right before the conditional branch.
@@ -495,9 +506,14 @@ private:
 
     cbranch_trace (rtx_insn *insn)
     : cbranch_insn (insn),
+      condition_rtx_in_insn (NULL),
       cbranch_type (unknown_branch_condition),
       setcc ()
     {
+      if (is_conditional_insn (cbranch_insn))
+       condition_rtx_in_insn = &XEXP (XEXP (PATTERN (cbranch_insn), 1), 0);
+      else if (rtx x = pc_set (cbranch_insn))
+       condition_rtx_in_insn = &XEXP (XEXP (x, 1), 0);
     }
 
     basic_block bb (void) const { return BLOCK_FOR_INSN (cbranch_insn); }
@@ -505,8 +521,16 @@ private:
     rtx
     branch_condition_rtx (void) const
     {
-      rtx x = pc_set (cbranch_insn);
-      return x == NULL_RTX ? NULL_RTX : XEXP (XEXP (x, 1), 0);
+      return condition_rtx_in_insn != NULL ? *condition_rtx_in_insn : NULL;
+    }
+    rtx&
+    branch_condition_rtx_ref (void) const
+    {
+      // Before anything gets to invoke this function, there are other checks
+      // in place to make sure that we have a known branch condition and thus
+      // the ref to the rtx in the insn.
+      gcc_assert (condition_rtx_in_insn != NULL);
+      return *condition_rtx_in_insn;
     }
 
     bool
@@ -1033,8 +1057,18 @@ sh_treg_combine::try_invert_branch_condition (cbranch_trace& trace)
 {
   log_msg ("inverting branch condition\n");
 
-  if (!invert_jump_1 (trace.cbranch_insn, JUMP_LABEL (trace.cbranch_insn)))
-    log_return (false, "invert_jump_1 failed\n");
+  rtx& comp = trace.branch_condition_rtx_ref ();
+
+  rtx_code rev_cmp_code = reversed_comparison_code (comp, trace.cbranch_insn);
+
+  if (rev_cmp_code == UNKNOWN)
+    log_return (false, "reversed_comparison_code = UNKNOWN\n");
+
+  validate_change (trace.cbranch_insn, &comp,
+                  gen_rtx_fmt_ee (rev_cmp_code,
+                                  GET_MODE (comp), XEXP (comp, 0),
+                                  XEXP (comp, 1)),
+                  1);
 
   if (verify_changes (num_validated_changes ()))
     confirm_change_group ();
@@ -1531,14 +1565,26 @@ sh_treg_combine::execute (function *fun)
   log_rtx (m_ccreg);
   log_msg ("  STORE_FLAG_VALUE = %d\n", STORE_FLAG_VALUE);
 
-  // Look for basic blocks that end with a conditional branch and try to
-  // optimize them.
+  // Look for basic blocks that end with a conditional branch or for
+  // conditional insns and try to optimize them.
   basic_block bb;
   FOR_EACH_BB_FN (bb, fun)
     {
-      rtx_insn *i = BB_END (bb);
+      rtx_insn* i = BB_END (bb);
+      if (i == NULL || i == PREV_INSN (BB_HEAD (bb)))
+       continue;
+
+      // A conditional branch is always the last insn of a basic block.
       if (any_condjump_p (i) && onlyjump_p (i))
-       try_optimize_cbranch (i);
+       {
+         try_optimize_cbranch (i);
+         i = PREV_INSN (i);
+       }
+
+      // Check all insns in block for conditional insns.
+      for (; i != NULL && i != PREV_INSN (BB_HEAD (bb)); i = PREV_INSN (i))
+       if (is_conditional_insn (i))
+         try_optimize_cbranch (i);
     }
 
   log_msg ("\n\n");