[optabs][ifcvt][1/3] Define negcc, notcc optabs
authorKyrylo Tkachov <kyrylo.tkachov@arm.com>
Tue, 10 Nov 2015 09:35:11 +0000 (09:35 +0000)
committerKyrylo Tkachov <ktkachov@gcc.gnu.org>
Tue, 10 Nov 2015 09:35:11 +0000 (09:35 +0000)
* ifcvt.c (noce_try_inverse_constants): New function.
(noce_process_if_block): Call it.
* optabs.h (emit_conditional_neg_or_complement): Declare prototype.
* optabs.def (negcc_optab, notcc_optab): Declare.
* optabs.c (emit_conditional_neg_or_complement): New function.
* doc/tm.texi (Standard Names): Document negcc, notcc names.

From-SVN: r230089

gcc/ChangeLog
gcc/doc/md.texi
gcc/ifcvt.c
gcc/optabs.c
gcc/optabs.def
gcc/optabs.h

index f9ae0601b791fd32287257d074c818eb77922d6a..2fe062aeb459e6ed3e001099e747f7e1300095a9 100644 (file)
@@ -1,3 +1,12 @@
+2015-11-10  Kyrylo Tkachov  <kyrylo.tkachov@arm.com>
+
+       * ifcvt.c (noce_try_inverse_constants): New function.
+       (noce_process_if_block): Call it.
+       * optabs.h (emit_conditional_neg_or_complement): Declare prototype.
+       * optabs.def (negcc_optab, notcc_optab): Declare.
+       * optabs.c (emit_conditional_neg_or_complement): New function.
+       * doc/tm.texi (Standard Names): Document negcc, notcc names.
+
 2015-11-10  Kyrylo Tkachov  <kyrylo.tkachov@arm.com>
 
        PR rtl-optimization/68236
index ee629e2338127de0b683bd89c884644156b8d90c..71a2791a60239b2acfd3f77707e7a9627d4e2ba2 100644 (file)
@@ -5805,6 +5805,21 @@ move operand 2 or (operands 2 + operand 3) into operand 0 according to the
 comparison in operand 1.  If the comparison is false, operand 2 is moved into
 operand 0, otherwise (operand 2 + operand 3) is moved.
 
+@cindex @code{neg@var{mode}cc} instruction pattern
+@item @samp{neg@var{mode}cc}
+Similar to @samp{mov@var{mode}cc} but for conditional negation.  Conditionally
+move the negation of operand 2 or the unchanged operand 3 into operand 0
+according to the comparison in operand 1.  If the comparison is true, the negation
+of operand 2 is moved into operand 0, otherwise operand 3 is moved.
+
+@cindex @code{not@var{mode}cc} instruction pattern
+@item @samp{not@var{mode}cc}
+Similar to @samp{neg@var{mode}cc} but for conditional complement.
+Conditionally move the bitwise complement of operand 2 or the unchanged
+operand 3 into operand 0 according to the comparison in operand 1.
+If the comparison is true, the complement of operand 2 is moved into
+operand 0, otherwise operand 3 is moved.
+
 @cindex @code{cstore@var{mode}4} instruction pattern
 @item @samp{cstore@var{mode}4}
 Store zero or nonzero in operand 0 according to whether a comparison
index c830b3cb8c4280586b09e63c7f6340c0b6b22709..56e4ed425764da31d8b8bca6840278c4504fc3b6 100644 (file)
@@ -1168,6 +1168,83 @@ noce_try_store_flag (struct noce_if_info *if_info)
     }
 }
 
+
+/* Convert "if (test) x = -A; else x = A" into
+   x = A; if (test) x = -x if the machine can do the
+   conditional negate form of this cheaply.
+   Try this before noce_try_cmove that will just load the
+   immediates into two registers and do a conditional select
+   between them.  If the target has a conditional negate or
+   conditional invert operation we can save a potentially
+   expensive constant synthesis.  */
+
+static bool
+noce_try_inverse_constants (struct noce_if_info *if_info)
+{
+  if (!noce_simple_bbs (if_info))
+    return false;
+
+  if (!CONST_INT_P (if_info->a)
+      || !CONST_INT_P (if_info->b)
+      || !REG_P (if_info->x))
+    return false;
+
+  machine_mode mode = GET_MODE (if_info->x);
+
+  HOST_WIDE_INT val_a = INTVAL (if_info->a);
+  HOST_WIDE_INT val_b = INTVAL (if_info->b);
+
+  rtx cond = if_info->cond;
+
+  rtx x = if_info->x;
+  rtx target;
+
+  start_sequence ();
+
+  rtx_code code;
+  if (val_b != HOST_WIDE_INT_MIN && val_a == -val_b)
+    code = NEG;
+  else if (val_a == ~val_b)
+    code = NOT;
+  else
+    {
+      end_sequence ();
+      return false;
+    }
+
+  rtx tmp = gen_reg_rtx (mode);
+  noce_emit_move_insn (tmp, if_info->a);
+
+  target = emit_conditional_neg_or_complement (x, code, mode, cond, tmp, tmp);
+
+  if (target)
+    {
+      rtx_insn *seq = get_insns ();
+
+      if (!seq)
+       {
+         end_sequence ();
+         return false;
+       }
+
+      if (target != if_info->x)
+       noce_emit_move_insn (if_info->x, target);
+
+       seq = end_ifcvt_sequence (if_info);
+
+       if (!seq)
+         return false;
+
+       emit_insn_before_setloc (seq, if_info->jump,
+                                INSN_LOCATION (if_info->insn_a));
+       return true;
+    }
+
+  end_sequence ();
+  return false;
+}
+
+
 /* Convert "if (test) x = a; else x = b", for A and B constant.
    Also allow A = y + c1, B = y + c2, with a common y between A
    and B.  */
@@ -3497,6 +3574,8 @@ noce_process_if_block (struct noce_if_info *if_info)
     goto success;
   if (noce_try_abs (if_info))
     goto success;
+  if (noce_try_inverse_constants (if_info))
+    goto success;
   if (!targetm.have_conditional_execution ()
       && noce_try_store_flag_constants (if_info))
     goto success;
index 79c5873ce368be64f72791ee510190ce98862f48..1e328a66f9173cd2e0109e827f7c9072f68958ab 100644 (file)
@@ -4210,6 +4210,56 @@ emit_conditional_move (rtx target, enum rtx_code code, rtx op0, rtx op1,
   return NULL_RTX;
 }
 
+
+/* Emit a conditional negate or bitwise complement using the
+   negcc or notcc optabs if available.  Return NULL_RTX if such operations
+   are not available.  Otherwise return the RTX holding the result.
+   TARGET is the desired destination of the result.  COMP is the comparison
+   on which to negate.  If COND is true move into TARGET the negation
+   or bitwise complement of OP1.  Otherwise move OP2 into TARGET.
+   CODE is either NEG or NOT.  MODE is the machine mode in which the
+   operation is performed.  */
+
+rtx
+emit_conditional_neg_or_complement (rtx target, rtx_code code,
+                                    machine_mode mode, rtx cond, rtx op1,
+                                    rtx op2)
+{
+  optab op = unknown_optab;
+  if (code == NEG)
+    op = negcc_optab;
+  else if (code == NOT)
+    op = notcc_optab;
+  else
+    gcc_unreachable ();
+
+  insn_code icode = direct_optab_handler (op, mode);
+
+  if (icode == CODE_FOR_nothing)
+    return NULL_RTX;
+
+  if (!target)
+    target = gen_reg_rtx (mode);
+
+  rtx_insn *last = get_last_insn ();
+  struct expand_operand ops[4];
+
+  create_output_operand (&ops[0], target, mode);
+  create_fixed_operand (&ops[1], cond);
+  create_input_operand (&ops[2], op1, mode);
+  create_input_operand (&ops[3], op2, mode);
+
+  if (maybe_expand_insn (icode, 4, ops))
+    {
+      if (ops[0].value != target)
+       convert_move (target, ops[0].value, false);
+
+      return target;
+    }
+  delete_insns_since (last);
+  return NULL_RTX;
+}
+
 /* Emit a conditional addition instruction if the machine supports one for that
    condition and machine mode.
 
index 888b21c4c648af82702bc1b3b01224ab559f0733..6fad6d9711e6e0b901b253c851a45ee352a86c00 100644 (file)
@@ -183,6 +183,8 @@ OPTAB_D (reload_out_optab, "reload_out$a")
 
 OPTAB_DC(cbranch_optab, "cbranch$a4", COMPARE)
 OPTAB_D (addcc_optab, "add$acc")
+OPTAB_D (negcc_optab, "neg$acc")
+OPTAB_D (notcc_optab, "not$acc")
 OPTAB_D (movcc_optab, "mov$acc")
 OPTAB_D (cmov_optab, "cmov$a6")
 OPTAB_D (cstore_optab, "cstore$a4")
index 3f29d1b6f79055074b0bc3098bebeea5c92f8741..5e6fe11ff00996e6aee68bf06a7f15bc2a167e43 100644 (file)
@@ -259,6 +259,10 @@ extern void emit_indirect_jump (rtx);
 rtx emit_conditional_move (rtx, enum rtx_code, rtx, rtx, machine_mode,
                           rtx, rtx, machine_mode, int);
 
+/* Emit a conditional negate or bitwise complement operation.  */
+rtx emit_conditional_neg_or_complement (rtx, rtx_code, machine_mode, rtx,
+                                        rtx, rtx);
+
 rtx emit_conditional_add (rtx, enum rtx_code, rtx, rtx, machine_mode,
                          rtx, rtx, machine_mode, int);