From patchwork Mon Nov 9 12:23:02 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kyrylo Tkachov X-Patchwork-Id: 56219 Delivered-To: patch@linaro.org Received: by 10.112.155.196 with SMTP id vy4csp147856lbb; Mon, 9 Nov 2015 04:23:24 -0800 (PST) X-Received: by 10.68.173.5 with SMTP id bg5mr39721692pbc.104.1447071804830; Mon, 09 Nov 2015 04:23:24 -0800 (PST) Return-Path: Received: from sourceware.org (server1.sourceware.org. [209.132.180.131]) by mx.google.com with ESMTPS id x8si22149678pbt.193.2015.11.09.04.23.24 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 09 Nov 2015 04:23:24 -0800 (PST) Received-SPF: pass (google.com: domain of gcc-patches-return-413228-patch=linaro.org@gcc.gnu.org designates 209.132.180.131 as permitted sender) client-ip=209.132.180.131; Authentication-Results: mx.google.com; spf=pass (google.com: domain of gcc-patches-return-413228-patch=linaro.org@gcc.gnu.org designates 209.132.180.131 as permitted sender) smtp.mailfrom=gcc-patches-return-413228-patch=linaro.org@gcc.gnu.org; dkim=pass header.i=@gcc.gnu.org DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :message-id:date:from:mime-version:to:cc:subject:content-type; q=dns; s=default; b=tk4UlBUojpeeAbQpHrpGPZkt5jA4WHU9uCEDQlTv/x6 ioD2cBvxyYIQUG7RY+EZbfxJ1CGhCUR3RNMWXTTzeweAMxBkdON8vqNCHDN9y4nv sJQVII+4vENhzPZ7iWRI6NjvQy/DW09Nai46is7MR3rDbi0qVTBHgsTY7Gq7nAOc = DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :message-id:date:from:mime-version:to:cc:subject:content-type; s=default; bh=C3duclOzimdfKrrEyh49wu5Mn7E=; b=Ai4zEfRQUAx2KAj0P 61KHcLQgaaZKfpsh23b3Wzt5lb0v+FdDW7wrHOOmLkHH9MkVgFgsW37Fjvb5aGxq Uhn/QSKxEw44HT2Ikjk902JegsKJsHjUaFO1jIb6vsWNAY2Mu/wKH/gXcvVP0ULJ ftLv35ajnjOQmWRIF4JvLWHQGo= Received: (qmail 67945 invoked by alias); 9 Nov 2015 12:23:12 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 67927 invoked by uid 89); 9 Nov 2015 12:23:10 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.7 required=5.0 tests=AWL, BAYES_00, SPF_PASS autolearn=ham version=3.3.2 X-HELO: eu-smtp-delivery-143.mimecast.com Received: from eu-smtp-delivery-143.mimecast.com (HELO eu-smtp-delivery-143.mimecast.com) (146.101.78.143) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Mon, 09 Nov 2015 12:23:08 +0000 Received: from cam-owa1.Emea.Arm.com (fw-tnat.cambridge.arm.com [217.140.96.140]) by eu-smtp-1.mimecast.com with ESMTP id uk-mta-25-ju-qIxj8REOZM3-ECc6Eag-1; Mon, 09 Nov 2015 12:23:03 +0000 Received: from [10.2.206.200] ([10.1.2.79]) by cam-owa1.Emea.Arm.com with Microsoft SMTPSVC(6.0.3790.3959); Mon, 9 Nov 2015 12:23:02 +0000 Message-ID: <56409026.1050506@arm.com> Date: Mon, 09 Nov 2015 12:23:02 +0000 From: Kyrill Tkachov User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:31.0) Gecko/20100101 Thunderbird/31.2.0 MIME-Version: 1.0 To: GCC Patches CC: Jeff Law Subject: [PATCH][optabs][ifcvt][1/3] Define negcc, notcc optabs X-MC-Unique: ju-qIxj8REOZM3-ECc6Eag-1 X-IsSubscribed: yes Hi all, This is a rebase of the patch I posted at: https://gcc.gnu.org/ml/gcc-patches/2015-09/msg00154.html The patch has been ok'd by Jeff but I wanted to hold off committing it until my fixes for the ifcvt regressions on sparc and x86_64 were fixed. The rebase conflicts were due to Richard's optabs splitting patch. I've also noticed that in my original patch I had a comparison of branch cost with the magic number '2'. I removed it from this version as it's not really meaningful. The transformation this patch enables is, at the moment, only supported for arm and aarch64 where it is always beneficial. If/when we have a proper ifcvt costing model (perhaps for GCC 7?) we'll update this accordingly if needed. Jeff, sorry for taking so long to commit this, I just wanted to fix the other ifcvt fallout before proceeding with more new functionality. I have also uncovered a bug in the arm implementation of these optabs (patch 3/3 in the series), so I'll post an updated version of that patch as well soon. Ok to commit this updated version instead? Bootstrapped and tested on arm, aarch64 and x86_64. It has been sitting in my tree for a couple of months now with no issues. Thanks, Kyrill 2015-11-09 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. commit 93cd987e9ab02ac68b44b2470bb5c4c6345efeca Author: Kyrylo Tkachov Date: Thu Aug 13 18:14:52 2015 +0100 [optabs][ifcvt][1/3] Define negcc, notcc optabs diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi index 619259f..c4e43f3 100644 --- a/gcc/doc/md.texi +++ b/gcc/doc/md.texi @@ -5791,6 +5791,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 157a716..1e773d8 100644 --- a/gcc/ifcvt.c +++ b/gcc/ifcvt.c @@ -1179,6 +1179,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. */ @@ -3190,6 +3267,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 c49d66b..e388d2a 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..5e6fe11 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);