From patchwork Mon Jun 23 06:59:11 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Zhenqiang Chen X-Patchwork-Id: 32323 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-qa0-f70.google.com (mail-qa0-f70.google.com [209.85.216.70]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id 041782055C for ; Mon, 23 Jun 2014 06:59:58 +0000 (UTC) Received: by mail-qa0-f70.google.com with SMTP id dc16sf18472682qab.9 for ; Sun, 22 Jun 2014 23:59:57 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:delivered-to:mailing-list:precedence:list-id :list-unsubscribe:list-archive:list-post:list-help:sender :delivered-to:mime-version:date:message-id:subject:from:to :x-original-sender:x-original-authentication-results:content-type; bh=Na/QbPd7bt09ODcVepSKV9oPbXq06/jBPoNcHjBjdZw=; b=PUDtkwPVwkXBTkMSoMSEI+RPT/UXnl7yPrC/3Nlbd7XPlDfg57VFtOlCuHCRfNkHmZ 8Dsw+TOAOU8fsdxzvLkKfP+zfHzBU7ZDGtz79/z0GjC58HhTF3lpQVkAdPV4aNiMajbc MTAhKbVQ0/6o5HxGoWqSzLsyAJf1/GgI6XO9jMnO2SpojflSTWU5wEicoWYmdJaod046 +UJjINeo96b5OxC2DsLgaWf7cTbSN/8YJwUcA3pg/uT7IaKStjLwDK1WnSlnMElXI/8x PUHnJStzqd01AUoKDwVneFSy0J72RZnvBSIN+GVUeLvGyRSGirGY/lPRU4omNK8RbGeg db6g== X-Gm-Message-State: ALoCoQkDKhpIDTxakkVa/z6LKG/06H0dA5EnOqoBQhpWWJxwIIYt1sTv7483Faqlw7ujaeuvoo7s X-Received: by 10.58.108.40 with SMTP id hh8mr9048966veb.18.1403506797866; Sun, 22 Jun 2014 23:59:57 -0700 (PDT) X-BeenThere: patchwork-forward@linaro.org Received: by 10.140.37.211 with SMTP id r77ls1820547qgr.10.gmail; Sun, 22 Jun 2014 23:59:57 -0700 (PDT) X-Received: by 10.58.107.146 with SMTP id hc18mr241345veb.37.1403506797769; Sun, 22 Jun 2014 23:59:57 -0700 (PDT) Received: from mail-ve0-x22f.google.com (mail-ve0-x22f.google.com [2607:f8b0:400c:c01::22f]) by mx.google.com with ESMTPS id tt2si8497324vdc.3.2014.06.22.23.59.57 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Sun, 22 Jun 2014 23:59:57 -0700 (PDT) Received-SPF: pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 2607:f8b0:400c:c01::22f as permitted sender) client-ip=2607:f8b0:400c:c01::22f; Received: by mail-ve0-f175.google.com with SMTP id jx11so5649832veb.6 for ; Sun, 22 Jun 2014 23:59:57 -0700 (PDT) X-Received: by 10.221.5.1 with SMTP id oe1mr17813419vcb.10.1403506797697; Sun, 22 Jun 2014 23:59:57 -0700 (PDT) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patch@linaro.org Received: by 10.221.37.5 with SMTP id tc5csp109921vcb; Sun, 22 Jun 2014 23:59:57 -0700 (PDT) X-Received: by 10.68.224.198 with SMTP id re6mr26345229pbc.8.1403506796930; Sun, 22 Jun 2014 23:59:56 -0700 (PDT) Received: from sourceware.org (server1.sourceware.org. [209.132.180.131]) by mx.google.com with ESMTPS id ww7si20487978pbc.36.2014.06.22.23.59.56 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sun, 22 Jun 2014 23:59:56 -0700 (PDT) Received-SPF: pass (google.com: domain of gcc-patches-return-370789-patch=linaro.org@gcc.gnu.org designates 209.132.180.131 as permitted sender) client-ip=209.132.180.131; Received: (qmail 11115 invoked by alias); 23 Jun 2014 06:59:44 -0000 Mailing-List: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org Precedence: list 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 11095 invoked by uid 89); 23 Jun 2014 06:59:43 -0000 X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.5 required=5.0 tests=AWL, BAYES_00, RCVD_IN_DNSWL_LOW, SPF_PASS autolearn=ham version=3.3.2 X-HELO: mail-lb0-f173.google.com Received: from mail-lb0-f173.google.com (HELO mail-lb0-f173.google.com) (209.85.217.173) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES128-SHA encrypted) ESMTPS; Mon, 23 Jun 2014 06:59:14 +0000 Received: by mail-lb0-f173.google.com with SMTP id s7so3857171lbd.4 for ; Sun, 22 Jun 2014 23:59:11 -0700 (PDT) MIME-Version: 1.0 X-Received: by 10.112.143.167 with SMTP id sf7mr15021542lbb.4.1403506751119; Sun, 22 Jun 2014 23:59:11 -0700 (PDT) Received: by 10.112.13.36 with HTTP; Sun, 22 Jun 2014 23:59:11 -0700 (PDT) Date: Mon, 23 Jun 2014 14:59:11 +0800 Message-ID: Subject: [PATCH, 4/10] expand ccmp From: Zhenqiang Chen To: "gcc-patches@gcc.gnu.org" X-IsSubscribed: yes X-Original-Sender: zhenqiang.chen@linaro.org X-Original-Authentication-Results: mx.google.com; spf=pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 2607:f8b0:400c:c01::22f as permitted sender) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org; dkim=pass header.i=@gcc.gnu.org X-Google-Group-Id: 836684582541 Hi, This patch includes the main logic to expand ccmp instructions. In the patch, * ccmp_candidate_p is used to identify the CCMP candidate * expand_ccmp_expr is the main entry, which calls expand_ccmp_expr_1 to expand CCMP. * expand_ccmp_expr_1 uses a recursive algorithm to expand CCMP. It calls gen_ccmp_first and gen_ccmp_next to generate CCMP instructions. During expanding, we must make sure that no instruction can clobber the CC reg except the compares. So clobber_cc_p and check_clobber_cc are introduced to do the check. * If the final result is not used in a COND_EXPR (checked by function used_in_cond_stmt_p), it calls cstorecc4 pattern to store the CC to a general register. Bootstrap and no make check regression on X86-64. OK for trunk? Thanks! -Zhenqiang ChangeLog: 2014-06-23 Zhenqiang Chen * ccmp.c (ccmp_candidate_p, used_in_cond_stmt_p, check_clobber_cc, clobber_cc_p, expand_ccmp_next, expand_ccmp_expr_1, expand_ccmp_expr): New functions to expand ccmp. * ccmp.h (expand_ccmp_expr): New prototype. * expr.c: #include "ccmp.h" (expand_expr_real_1): Try to expand ccmp. ops.op0 = gimple_assign_rhs1 (g); diff --git a/gcc/ccmp.c b/gcc/ccmp.c index 665c2a5..97b3910 100644 --- a/gcc/ccmp.c +++ b/gcc/ccmp.c @@ -47,6 +47,262 @@ along with GCC; see the file COPYING3. If not see #include "expmed.h" #include "ccmp.h" +/* The following functions expand conditional compare (CCMP) instructions. + Here is a short description about the over all algorithm: + * ccmp_candidate_p is used to identify the CCMP candidate + + * expand_ccmp_expr is the main entry, which calls expand_ccmp_expr_1 + to expand CCMP. + + * expand_ccmp_expr_1 uses a recursive algorithm to expand CCMP. + It calls two target hooks gen_ccmp_first and gen_ccmp_next to generate + CCMP instructions. + - gen_ccmp_first expands the first compare in CCMP. + - gen_ccmp_next expands the following compares. + + During expanding, we must make sure that no instruction can clobber the + CC reg except the compares. So clobber_cc_p and check_clobber_cc are + introduced to do the check. + + * If the final result is not used in a COND_EXPR (checked by function + used_in_cond_stmt_p), it calls cstorecc4 pattern to store the CC to a + general register. */ + +/* Check whether G is a potential conditional compare candidate. */ +static bool +ccmp_candidate_p (gimple g) +{ + tree rhs = gimple_assign_rhs_to_tree (g); + tree lhs, op0, op1; + gimple gs0, gs1; + enum tree_code tcode, tcode0, tcode1; + tcode = TREE_CODE (rhs); + + if (tcode != BIT_AND_EXPR && tcode != BIT_IOR_EXPR) + return false; + + lhs = gimple_assign_lhs (g); + op0 = TREE_OPERAND (rhs, 0); + op1 = TREE_OPERAND (rhs, 1); + + if ((TREE_CODE (op0) != SSA_NAME) || (TREE_CODE (op1) != SSA_NAME) + || !has_single_use (lhs)) + return false; + + gs0 = get_gimple_for_ssa_name (op0); + gs1 = get_gimple_for_ssa_name (op1); + if (!gs0 || !gs1 || !is_gimple_assign (gs0) || !is_gimple_assign (gs1) + /* g, gs0 and gs1 must be in the same basic block, since current stage + is out-of-ssa. We can not guarantee the correctness when forwording + the gs0 and gs1 into g whithout DATAFLOW analysis. */ + || gimple_bb (gs0) != gimple_bb (gs1) + || gimple_bb (gs0) != gimple_bb (g)) + return false; + + if (!(INTEGRAL_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (gs0))) + || POINTER_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (gs0)))) + || !(INTEGRAL_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (gs1))) + || POINTER_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (gs1))))) + return false; + + tcode0 = gimple_assign_rhs_code (gs0); + tcode1 = gimple_assign_rhs_code (gs1); + if (TREE_CODE_CLASS (tcode0) == tcc_comparison + && TREE_CODE_CLASS (tcode1) == tcc_comparison) + return true; + if (TREE_CODE_CLASS (tcode0) == tcc_comparison + && ccmp_candidate_p (gs1)) + return true; + else if (TREE_CODE_CLASS (tcode1) == tcc_comparison + && ccmp_candidate_p (gs0)) + return true; + /* We skip ccmp_candidate_p (gs1) && ccmp_candidate_p (gs0) since + there is no way to set the CC flag. */ + return false; +} + +/* Check whether EXP is used in a GIMPLE_COND statement or not. */ +static bool +used_in_cond_stmt_p (tree exp) +{ + bool expand_cond = false; + imm_use_iterator ui; + gimple use_stmt; + FOR_EACH_IMM_USE_STMT (use_stmt, ui, exp) + if (gimple_code (use_stmt) == GIMPLE_COND) + { + tree op1 = gimple_cond_rhs (use_stmt); + if (integer_zerop (op1)) + expand_cond = true; + BREAK_FROM_IMM_USE_STMT (ui); + } + return expand_cond; +} + +/* If SETTER clobber CC reg, set DATA to TRUE. */ +static void +check_clobber_cc (rtx reg, const_rtx setter, void *data) +{ + if (GET_CODE (setter) == CLOBBER && GET_MODE (reg) == CCmode) + *(bool *)data = true; +} + +/* Check whether INSN and all its NEXT_INSN clobber CC reg or not. */ +static bool +clobber_cc_p (rtx insn) +{ + bool clobber = false; + for (; insn; insn = NEXT_INSN (insn)) + { + note_stores (PATTERN (insn), check_clobber_cc, &clobber); + if (clobber) + return true; + } + return false; +} + +/* Help function to generate conditional compare. PREV is the result of + GEN_CCMP_FIRST or GEN_CCMP_NEXT. G is the next compare. + CODE is BIT_AND_EXPR or BIT_IOR_EXPR. */ +static rtx +expand_ccmp_next (rtx prev, gimple g, enum tree_code code) +{ + rtx op0, op1; + int unsignedp = TYPE_UNSIGNED (TREE_TYPE (gimple_assign_rhs1 (g))); + enum rtx_code rcode = get_rtx_code (gimple_assign_rhs_code (g), unsignedp); + rtx last = get_last_insn (); + + expand_operands (gimple_assign_rhs1 (g), + gimple_assign_rhs2 (g), + NULL_RTX, &op0, &op1, EXPAND_NORMAL); + + /* If any operand clobbers CC reg, we will give up. */ + if (clobber_cc_p (NEXT_INSN (last))) + return NULL_RTX; + + return targetm.gen_ccmp_next (prev, rcode, op0, op1, get_rtx_code (code, 0)); +} + +/* Expand conditional compare gimple G. A typical CCMP sequence is like: + + CC0 = CMP (a, b); + CC1 = CCMP (NE (CC0, 0), CMP (e, f)); + ... + CCn = CCMP (NE (CCn-1, 0), CMP (...)); + + hook gen_ccmp_first is used to expand the first compare. + hook gen_ccmp_next is used to expand the following CCMP. */ +static rtx +expand_ccmp_expr_1 (gimple g) +{ + tree exp = gimple_assign_rhs_to_tree (g); + enum tree_code code = TREE_CODE (exp); + gimple gs0 = get_gimple_for_ssa_name (TREE_OPERAND (exp, 0)); + gimple gs1 = get_gimple_for_ssa_name (TREE_OPERAND (exp, 1)); + rtx tmp; + enum tree_code code0 = gimple_assign_rhs_code (gs0); + enum tree_code code1 = gimple_assign_rhs_code (gs1); + + gcc_assert (code == BIT_AND_EXPR || code == BIT_IOR_EXPR); + gcc_assert (gs0 && gs1 && is_gimple_assign (gs0) && is_gimple_assign (gs1)); + + if (TREE_CODE_CLASS (code0) == tcc_comparison) + { + if (TREE_CODE_CLASS (code1) == tcc_comparison) + { + int unsignedp0, unsignedp1; + enum rtx_code rcode0, rcode1; + rtx op0, op1, op2, op3, tmp; + + unsignedp0 = TYPE_UNSIGNED (TREE_TYPE (gimple_assign_rhs1 (gs0))); + rcode0 = get_rtx_code (code0, unsignedp0); + unsignedp1 = TYPE_UNSIGNED (TREE_TYPE (gimple_assign_rhs1 (gs1))); + rcode1 = get_rtx_code (code1, unsignedp1); + + expand_operands (gimple_assign_rhs1 (gs0), + gimple_assign_rhs2 (gs0), + NULL_RTX, &op0, &op1, EXPAND_NORMAL); + + /* Since the operands of GS1 might clobber CC reg, we expand the + operands of GS1 before GEN_CCMP_FIRST. */ + expand_operands (gimple_assign_rhs1 (gs1), + gimple_assign_rhs2 (gs1), + NULL_RTX, &op2, &op3, EXPAND_NORMAL); + tmp = targetm.gen_ccmp_first (rcode0, op0, op1); + if (!tmp) + return NULL_RTX; + + return targetm.gen_ccmp_next (tmp, rcode1, op2, op3, + get_rtx_code (code, 0)); + } + else + { + gcc_assert (code1 == BIT_AND_EXPR || code1 == BIT_IOR_EXPR); + + /* Note: We swap the order to make the recursive function work. */ + tmp = expand_ccmp_expr_1 (gs1); + if (tmp) + return expand_ccmp_next (tmp, gs0, code); + } + } + else + { + gcc_assert (gimple_assign_rhs_code (gs0) == BIT_AND_EXPR + || gimple_assign_rhs_code (gs0) == BIT_IOR_EXPR); + if (TREE_CODE_CLASS (gimple_assign_rhs_code (gs1)) == tcc_comparison) + { + tmp = expand_ccmp_expr_1 (gs0); + if (tmp) + return expand_ccmp_next (tmp, gs1, code); + } + else + { + gcc_assert (gimple_assign_rhs_code (gs1) == BIT_AND_EXPR + || gimple_assign_rhs_code (gs1) == BIT_IOR_EXPR); + } + } + + return NULL_RTX; +} + +rtx +expand_ccmp_expr (gimple g) +{ + rtx last, tmp; + + if (!ccmp_candidate_p (g)) + return NULL_RTX; + + last = get_last_insn (); + tmp = expand_ccmp_expr_1 (g); + + if (tmp) + { + enum insn_code icode; + tree lhs = gimple_assign_lhs (g); + /* TMP should be CC. If it is used in a GIMPLE_COND, just return it. + Note: Target needs to define "cbranchcc4". */ + if (used_in_cond_stmt_p (lhs)) + return tmp; + + /* If TMP is not used in a GIMPLE_COND, store it with a csctorecc4_optab. + Note: Target needs to define "cstorecc4". */ + icode = optab_handler (cstore_optab, CCmode); + if (icode != CODE_FOR_nothing) + { + rtx target = gen_reg_rtx (word_mode); + tmp = emit_cstore (target, icode, NE, CCmode, CCmode, + 0, tmp, const0_rtx, 1, word_mode); + if (tmp) + return tmp; + } + } + + /* Clean up. */ + delete_insns_since (last); + return NULL_RTX; +} + bool ccmp_insn_p (rtx object) { diff --git a/gcc/ccmp.h b/gcc/ccmp.h index 7e139aa..56f3ac2 100644 --- a/gcc/ccmp.h +++ b/gcc/ccmp.h @@ -20,6 +20,8 @@ along with GCC; see the file COPYING3. If not see #ifndef GCC_CCMP_H #define GCC_CCMP_H +extern rtx expand_ccmp_expr (gimple); + extern bool ccmp_insn_p (rtx); #endif /* GCC_CCMP_H */ diff --git a/gcc/expr.c b/gcc/expr.c index 04cf56e..4c31521 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -68,6 +68,7 @@ along with GCC; see the file COPYING3. If not see #include "tree-ssa-address.h" #include "cfgexpand.h" #include "builtins.h" +#include "ccmp.h" #ifndef STACK_PUSH_CODE #ifdef STACK_GROWS_DOWNWARD @@ -9379,6 +9380,15 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, /* Fallthru */ case GIMPLE_BINARY_RHS: ops.op1 = gimple_assign_rhs2 (g); + + /* Try to expand conditonal compare. */ + if (targetm.gen_ccmp_first != NULL) + { + gcc_checking_assert (targetm.gen_ccmp_next != NULL); + r = expand_ccmp_expr (g); + if (r) + break; + } /* Fallthru */ case GIMPLE_UNARY_RHS: