From ce68b5cfb9d12cb55345bd26ee9114aee925d46a Mon Sep 17 00:00:00 2001 From: Kyrylo Tkachov Date: Tue, 10 Nov 2015 09:35:11 +0000 Subject: [PATCH] [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 --- gcc/ChangeLog | 9 ++++++ gcc/doc/md.texi | 15 ++++++++++ gcc/ifcvt.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++++ gcc/optabs.c | 50 +++++++++++++++++++++++++++++++ gcc/optabs.def | 2 ++ gcc/optabs.h | 4 +++ 6 files changed, 159 insertions(+) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index f9ae0601b79..2fe062aeb45 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,12 @@ +2015-11-10 Kyrylo Tkachov + + * 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 PR rtl-optimization/68236 diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi index ee629e23381..71a2791a602 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 c830b3cb8c4..56e4ed42576 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 79c5873ce36..1e328a66f91 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 888b21c4c64..6fad6d9711e 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 3f29d1b6f79..5e6fe11ff00 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); -- 2.30.2