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: 362668 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 50B5F14009B for ; Mon, 23 Jun 2014 16:59:51 +1000 (EST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :mime-version:date:message-id:subject:from:to:content-type; q= dns; s=default; b=Tum2KCMoWQCthOQxuIlUuHGrSo1Aa5KFNFixEdfOZZuuSJ tcta5mcYk4J7ZQWsDd1QiM/iQBKnp30qadqydmq4OeJCcc12KS23dphAeC54umGp 7xPuPLrTLndIJxjBlgNNNQ6tM1mjYS1MlEzWAAloxUJOzZ8Zz73oc4JLYo+ZI= 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 :mime-version:date:message-id:subject:from:to:content-type; s= default; bh=QYFXUizpw6qnj0SL8MHHwyQwvhw=; b=WFNOO20ZC2XW3lQkbaWQ meTdteuOZlTKF03msn1O4XlWcaoo/MXXSKKwYviRBabdQcuajNTo/cL5KlEabndJ 4msKe3LqUHh8dyzoN8QgFtDi6TZ+PdnB9wJvUxC3NQhQ0QuxgWdAU/pcCZp2KXcz wFgKenrQu7ed5eMzeQELEWk= Received: (qmail 11115 invoked by alias); 23 Jun 2014 06:59:44 -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 11095 invoked by uid 89); 23 Jun 2014 06:59:43 -0000 Authentication-Results: sourceware.org; auth=none 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) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:date:message-id:subject:from:to :content-type; bh=Na/QbPd7bt09ODcVepSKV9oPbXq06/jBPoNcHjBjdZw=; b=Y3CtnOatC0HFIc+bRRXalvXgiQ/bn93jWmsbsOJi1l6Md0dD+IaQLVRly5KSNhF82V f9aBx2HvNt6lKK7Eo8dML1rmVPnZJhQEAPCXyP5CoCo/RUfFvS25g5QSoHzg6nQXzj7+ WbCU16vWNXYYOtCgkxMmXCzcxKeEQMYKTfCCk99xNLInfYv2FBqAaXmZgaXzAJOnoU0w OXXhNIm5v+pgnY7rmU7eQDH4yuvkMDzQZUOPsa9J/MVgRgkEo/YhdcRbHMT31De0MXJR Ey4aJF7J5Zx7yq/OUj+Jqne4EaFnKA9r8rNPryMdMFZtpZEfN20j/0RodoF+R6REfeKO HNSw== X-Gm-Message-State: ALoCoQlRxU320freEGOnAit8S5L8DKfFL3ZD2myEz99unZoRx3zEMayCB+chQrJ08/vo80eXOjRt 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 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: