aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorKyrylo Tkachov <kyrylo.tkachov@arm.com>2015-11-10 09:35:11 +0000
committerKyrylo Tkachov <ktkachov@gcc.gnu.org>2015-11-10 09:35:11 +0000
commitce68b5cfb9d12cb55345bd26ee9114aee925d46a (patch)
treef7660813bbcbf78ce1bf2c64cd6933e5e449b3b0 /gcc
parentdf554b0e49e59c974e45ab21a3a2b4295ce348b2 (diff)
downloadgcc-ce68b5cfb9d12cb55345bd26ee9114aee925d46a.zip
gcc-ce68b5cfb9d12cb55345bd26ee9114aee925d46a.tar.gz
gcc-ce68b5cfb9d12cb55345bd26ee9114aee925d46a.tar.bz2
[optabs][ifcvt][1/3] Define negcc, notcc optabs
* 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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog9
-rw-r--r--gcc/doc/md.texi15
-rw-r--r--gcc/ifcvt.c79
-rw-r--r--gcc/optabs.c50
-rw-r--r--gcc/optabs.def2
-rw-r--r--gcc/optabs.h4
6 files changed, 159 insertions, 0 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index f9ae060..2fe062a 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,14 @@
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
* haifa-sched.c (autopref_multipass_dfa_lookahead_guard): Return 0
if insn_queue doesn't exist.
diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi
index ee629e2..71a2791 100644
--- a/gcc/doc/md.texi
+++ b/gcc/doc/md.texi
@@ -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
diff --git a/gcc/ifcvt.c b/gcc/ifcvt.c
index c830b3c..56e4ed42 100644
--- a/gcc/ifcvt.c
+++ b/gcc/ifcvt.c
@@ -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;
diff --git a/gcc/optabs.c b/gcc/optabs.c
index 79c5873..1e328a6 100644
--- a/gcc/optabs.c
+++ b/gcc/optabs.c
@@ -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.
diff --git a/gcc/optabs.def b/gcc/optabs.def
index 888b21c..6fad6d9 100644
--- a/gcc/optabs.def
+++ b/gcc/optabs.def
@@ -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")
diff --git a/gcc/optabs.h b/gcc/optabs.h
index 3f29d1b..5e6fe11f 100644
--- a/gcc/optabs.h
+++ b/gcc/optabs.h
@@ -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);