From patchwork Mon Feb 24 09:18:16 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Zhenqiang Chen X-Patchwork-Id: 25178 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-qg0-f69.google.com (mail-qg0-f69.google.com [209.85.192.69]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id B8CE1203C4 for ; Mon, 24 Feb 2014 09:18:37 +0000 (UTC) Received: by mail-qg0-f69.google.com with SMTP id j107sf7438722qga.0 for ; Mon, 24 Feb 2014 01:18:37 -0800 (PST) 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:cc :x-original-sender:x-original-authentication-results:content-type; bh=zYKkUPto4B9x6GCxcIXyhJRn3bzzW8Fu5r6ApNqElKQ=; b=dmAbAxTQiDZk1ay4gRbk0KtuRSKZLyRBsb4bbTPk7qoFj/ytKtWyyr/K8z3h6HNjJf sdxsMHjPPmiXcuUoFJe3oEppCcsBI90iWxn/tn5GhxphxjgNPqki/08eUrqzc8noQppw LcX3ToZpIZuwSXZQQtdRWJZyjjScmFfj4T46mK3Sz1zBzxeXIoVL5bcYbPlDgEbELVcn 4pinjJtCKMgg3EaGVFnE7f+90DZt9kFxKnxhWybqRD1aOVRXzbgoqtUhC3Z5vD+v6jDq TSyjpb4GGKT9mRxA6cFsm5eMV+nst1vO14HWaLLIDdwfqeWTDm23vXXeUyoIr+ZTePXS tGhw== X-Gm-Message-State: ALoCoQkOss1jJ7VxHPyeNo9mHsrhzTsMXMP58VOIYgMwWGAFgFpLnIMkNCKH2hY32pMaFd4x6P3j X-Received: by 10.224.4.202 with SMTP id 10mr10259106qas.7.1393233517563; Mon, 24 Feb 2014 01:18:37 -0800 (PST) X-BeenThere: patchwork-forward@linaro.org Received: by 10.140.38.241 with SMTP id t104ls1104065qgt.21.gmail; Mon, 24 Feb 2014 01:18:37 -0800 (PST) X-Received: by 10.52.99.227 with SMTP id et3mr9798298vdb.53.1393233517430; Mon, 24 Feb 2014 01:18:37 -0800 (PST) Received: from mail-vc0-x232.google.com (mail-vc0-x232.google.com [2607:f8b0:400c:c03::232]) by mx.google.com with ESMTPS id u1si5679588vek.67.2014.02.24.01.18.37 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Mon, 24 Feb 2014 01:18:37 -0800 (PST) Received-SPF: neutral (google.com: 2607:f8b0:400c:c03::232 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) client-ip=2607:f8b0:400c:c03::232; Received: by mail-vc0-f178.google.com with SMTP id ik5so5459331vcb.23 for ; Mon, 24 Feb 2014 01:18:37 -0800 (PST) X-Received: by 10.52.23.68 with SMTP id k4mr9948753vdf.24.1393233517239; Mon, 24 Feb 2014 01:18:37 -0800 (PST) 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.220.174.196 with SMTP id u4csp48000vcz; Mon, 24 Feb 2014 01:18:36 -0800 (PST) X-Received: by 10.68.221.42 with SMTP id qb10mr23792594pbc.65.1393233515915; Mon, 24 Feb 2014 01:18:35 -0800 (PST) Received: from sourceware.org (server1.sourceware.org. [209.132.180.131]) by mx.google.com with ESMTPS id mp8si16286036pbc.22.2014.02.24.01.18.35 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 24 Feb 2014 01:18:35 -0800 (PST) Received-SPF: pass (google.com: domain of gcc-patches-return-362276-patch=linaro.org@gcc.gnu.org designates 209.132.180.131 as permitted sender) client-ip=209.132.180.131; Received: (qmail 12775 invoked by alias); 24 Feb 2014 09:18:22 -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 12762 invoked by uid 89); 24 Feb 2014 09:18:21 -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-la0-f49.google.com Received: from mail-la0-f49.google.com (HELO mail-la0-f49.google.com) (209.85.215.49) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES128-SHA encrypted) ESMTPS; Mon, 24 Feb 2014 09:18:19 +0000 Received: by mail-la0-f49.google.com with SMTP id mc6so1773928lab.22 for ; Mon, 24 Feb 2014 01:18:16 -0800 (PST) MIME-Version: 1.0 X-Received: by 10.152.44.225 with SMTP id h1mr11377321lam.71.1393233496239; Mon, 24 Feb 2014 01:18:16 -0800 (PST) Received: by 10.112.173.137 with HTTP; Mon, 24 Feb 2014 01:18:16 -0800 (PST) Date: Mon, 24 Feb 2014 17:18:16 +0800 Message-ID: Subject: [PATCH 2/n] Add conditional compare support for ARM From: Zhenqiang Chen To: "gcc-patches@gcc.gnu.org" Cc: Ramana Radhakrishnan , Richard Earnshaw X-IsSubscribed: yes X-Original-Sender: zhenqiang.chen@linaro.org X-Original-Authentication-Results: mx.google.com; spf=neutral (google.com: 2607:f8b0:400c:c03::232 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org; dkim=pass header.i=@gcc.gnu.org X-Google-Group-Id: 836684582541 Hi, Here is the patch for ARM to generate conditional compare during expand, which is extracted from previous discussion (http://gcc.gnu.org/ml/gcc-patches/2014-11/msg03622.html). Bootstrap and no make check regression on ARM Chrome book. Is it OK for next stage1? Thanks! -Zhenqiang ChangeLog: 2014-02-24 Zhenqiang Chen * config/arm/arm-protos.h (arm_select_dominance_ccmp_mode, arm_ccmode_to_code): New prototypes. * config/arm/arm.c (arm_select_dominance_cc_mode_1): New function extracted from arm_select_dominance_cc_mode. (arm_ccmode_to_code, arm_code_to_ccmode, arm_convert_to_SImode, arm_select_dominance_ccmp_mode): New functions. (arm_select_ccmp_cmp_order, arm_gen_ccmp_first, arm_gen_ccmp_next): New hooks. (arm_select_dominance_cc_mode): Call arm_select_dominance_cc_mode_1. * config/arm/arm.md (cbranchcc4, cstorecc4, ccmp_and, ccmp_ior): New instruction patterns. diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h index 13874ee..463e3d4 100644 --- a/gcc/config/arm/arm-protos.h +++ b/gcc/config/arm/arm-protos.h @@ -117,6 +117,9 @@ extern bool gen_movmem_ldrd_strd (rtx *); extern enum machine_mode arm_select_cc_mode (RTX_CODE, rtx, rtx); extern enum machine_mode arm_select_dominance_cc_mode (rtx, rtx, HOST_WIDE_INT); +extern enum machine_mode arm_select_dominance_ccmp_mode (rtx, enum machine_mode, + HOST_WIDE_INT); +enum rtx_code arm_ccmode_to_code (enum machine_mode mode); extern rtx arm_gen_compare_reg (RTX_CODE, rtx, rtx, rtx); extern rtx arm_gen_return_addr_mask (void); extern void arm_reload_in_hi (rtx *); diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c index b562986..bf0d53c 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -287,6 +287,12 @@ static unsigned arm_add_stmt_cost (void *data, int count, static void arm_canonicalize_comparison (int *code, rtx *op0, rtx *op1, bool op0_preserve_value); static unsigned HOST_WIDE_INT arm_asan_shadow_offset (void); +static int arm_select_ccmp_cmp_order (int, int); +static rtx arm_gen_ccmp_first (int, rtx, rtx); +static rtx arm_gen_ccmp_next (rtx, int, rtx, rtx, int); +static enum machine_mode arm_select_dominance_cc_mode_1 (enum rtx_code cond1, + enum rtx_code cond2, + HOST_WIDE_INT); /* Table of machine attributes. */ static const struct attribute_spec arm_attribute_table[] = @@ -675,6 +681,15 @@ static const struct attribute_spec arm_attribute_table[] = #undef TARGET_CAN_USE_DOLOOP_P #define TARGET_CAN_USE_DOLOOP_P can_use_doloop_if_innermost +#undef TARGET_SELECT_CCMP_CMP_ORDER +#define TARGET_SELECT_CCMP_CMP_ORDER arm_select_ccmp_cmp_order + +#undef TARGET_GEN_CCMP_FIRST +#define TARGET_GEN_CCMP_FIRST arm_gen_ccmp_first + +#undef TARGET_GEN_CCMP_NEXT +#define TARGET_GEN_CCMP_NEXT arm_gen_ccmp_next + struct gcc_target targetm = TARGET_INITIALIZER; /* Obstack for minipool constant handling. */ @@ -937,7 +952,6 @@ struct processors const struct tune_params *const tune; }; - #define ARM_PREFETCH_NOT_BENEFICIAL 0, -1, -1 #define ARM_PREFETCH_BENEFICIAL(prefetch_slots,l1_size,l1_line_size) \ prefetch_slots, \ @@ -14554,7 +14568,13 @@ arm_select_dominance_cc_mode (rtx x, rtx y, HOST_WIDE_INT cond_or) cond1 = cond2; cond2 = temp; } + return arm_select_dominance_cc_mode_1 (cond1, cond2, cond_or); +} +static enum machine_mode +arm_select_dominance_cc_mode_1 (enum rtx_code cond1, enum rtx_code cond2, + HOST_WIDE_INT cond_or) +{ switch (cond1) { case EQ: @@ -14635,8 +14655,7 @@ arm_select_dominance_cc_mode (rtx x, rtx y, HOST_WIDE_INT cond_or) gcc_unreachable (); } - /* The remaining cases only occur when both comparisons are the - same. */ + /* The remaining cases only occur when both comparisons are the same. */ case NE: gcc_assert (cond1 == cond2); return CC_DNEmode; @@ -14662,6 +14681,198 @@ arm_select_dominance_cc_mode (rtx x, rtx y, HOST_WIDE_INT cond_or) } } +enum rtx_code +arm_ccmode_to_code (enum machine_mode mode) +{ + switch (mode) + { + case CC_DNEmode: + return NE; + case CC_DEQmode: + return EQ; + case CC_DLEmode: + return LE; + case CC_DLTmode: + return LT; + case CC_DGEmode: + return GE; + case CC_DGTmode: + return GT; + case CC_DLEUmode: + return LEU; + case CC_DLTUmode: + return LTU; + case CC_DGEUmode: + return GEU; + case CC_DGTUmode: + return GTU; + default: + return UNKNOWN; + } +} + +static enum machine_mode +arm_code_to_ccmode (enum rtx_code code) +{ + switch (code) + { + case NE: + return CC_DNEmode; + case EQ: + return CC_DEQmode; + case LE: + return CC_DLEmode; + case LT: + return CC_DLTmode; + case GE: + return CC_DGEmode; + case GT: + return CC_DGTmode; + case LEU: + return CC_DLEUmode; + case LTU: + return CC_DLTUmode; + case GEU: + return CC_DGEUmode; + case GTU: + return CC_DGTUmode; + default: + return CCmode; + } +} + +/* MODE is the CC mode result of the previous conditional compare. + X is the next compare. */ +enum machine_mode +arm_select_dominance_ccmp_mode (rtx x, enum machine_mode mode, + HOST_WIDE_INT cond_or) +{ + enum rtx_code cond1 = arm_ccmode_to_code (mode); + enum rtx_code cond2; + + if (cond1 == UNKNOWN) + return CCmode; + + /* Currently we will probably get the wrong result if the individual + comparisons are not simple. */ + if (arm_select_cc_mode (cond2 = GET_CODE (x), XEXP (x, 0), XEXP (x, 1)) + != CCmode) + return CCmode; + + /* If the comparisons are not equal, and one doesn't dominate the other, + then we can't do this. Since there is a conditional compare before + current insn, we can not swap the compares. So we have to check the + dominate relation separately for DOM_CC_X_OR_Y and DOM_CC_X_AND_Y. */ + if (cond1 != cond2 + && !(cond_or == DOM_CC_X_OR_Y ? comparison_dominates_p (cond1, cond2) + : comparison_dominates_p (cond2, cond1))) + return CCmode; + + if (cond_or == DOM_CC_X_OR_Y) + return arm_select_dominance_cc_mode_1 (cond1, cond2, cond_or); + else + return arm_select_dominance_cc_mode_1 (cond2, cond1, cond_or); +} + +/* COND1 and COND2 should be enum rtx_code, which represent two compares. + There are order sensitive for conditional compare. It returns + 1: Keep current order. + -1: Swap the two compares. + 0: Invalid combination. */ + +static int +arm_select_ccmp_cmp_order (int cond1, int cond2) +{ + /* THUMB1 does not support conditional compare. */ + if (TARGET_THUMB1) + return 0; + + if (cond1 == cond2) + return 1; + if (comparison_dominates_p ((enum rtx_code) cond1, (enum rtx_code) cond2)) + return -1; + if (comparison_dominates_p ((enum rtx_code) cond2, (enum rtx_code) cond1)) + return 1; + + return 0; +} + +/* Conver QImode or HImode OP0 and OP1 to SImode. If the final OP0 and OP1 + are not SImode, return FALSE. */ +static bool +arm_convert_to_SImode (rtx* op0, rtx* op1, int unsignedp) +{ + enum machine_mode mode; + + mode = GET_MODE (*op0); + if (mode == VOIDmode) + mode = GET_MODE (*op1); + + if (mode == QImode || mode == HImode) + { + *op0 = convert_modes (SImode, mode, *op0, unsignedp); + *op1 = convert_modes (SImode, mode, *op1, unsignedp); + } + else if (mode != SImode) + return false; + + return true; +} + +static rtx +arm_gen_ccmp_first (int code, rtx op0, rtx op1) +{ + enum machine_mode mode; + rtx cmp, target; + int unsignedp = code == LTU || code == LEU || code == GTU || code == GEU; + + if (!arm_convert_to_SImode (&op0, &op1, unsignedp) + || !s_register_operand (op0, SImode) + || !arm_add_operand (op1, SImode)) + return NULL_RTX; + + mode = arm_code_to_ccmode ((enum rtx_code) code); + if (mode == CCmode) + return NULL_RTX; + + cmp = gen_rtx_fmt_ee (COMPARE, CCmode, op0, op1); + target = gen_rtx_REG (mode, CC_REGNUM); + emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_REG (CCmode, CC_REGNUM), cmp)); + return target; +} + +static rtx +arm_gen_ccmp_next (rtx prev, int cmp_code, rtx op0, rtx op1, int bit_code) +{ + rtx cmp0, cmp1, target, bit_op; + HOST_WIDE_INT cond_or; + enum machine_mode mode; + int unsignedp = cmp_code == LTU || cmp_code == LEU + || cmp_code == GTU || cmp_code == GEU; + + if (!arm_convert_to_SImode (&op0, &op1, unsignedp) + || !s_register_operand (op0, SImode) + || !arm_add_operand (op1, SImode)) + return NULL_RTX; + + cmp1 = gen_rtx_fmt_ee ((enum rtx_code) cmp_code, SImode, op0, op1); + cond_or = bit_code == AND ? DOM_CC_X_AND_Y : DOM_CC_X_OR_Y; + mode = arm_select_dominance_ccmp_mode (cmp1, GET_MODE (prev), cond_or); + if (mode == CCmode) + return NULL_RTX; + + cmp0 = gen_rtx_fmt_ee (NE, SImode, prev, const0_rtx); + + bit_op = gen_rtx_fmt_ee ((enum rtx_code) bit_code, SImode, cmp0, cmp1); + + /* Generate insn to match ccmp_and/ccmp_ior. */ + target = gen_rtx_REG (mode, CC_REGNUM); + emit_insn (gen_rtx_SET (VOIDmode, target, + gen_rtx_fmt_ee (COMPARE, VOIDmode, + bit_op, const0_rtx))); + return target; +} + enum machine_mode arm_select_cc_mode (enum rtx_code op, rtx x, rtx y) { diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md index 2ddda02..ef55bd3 100644 --- a/gcc/config/arm/arm.md +++ b/gcc/config/arm/arm.md @@ -12926,3 +12926,122 @@ (include "sync.md") ;; Fixed-point patterns (include "arm-fixed.md") + +(define_expand "cbranchcc4" + [(set (pc) (if_then_else + (match_operator 0 "expandable_comparison_operator" + [(match_operand 1 "dominant_cc_register" "") + (const_int 0)]) + (label_ref (match_operand 3 "" "")) + (pc)))] + "TARGET_32BIT" + " ") + +(define_expand "cstorecc4" + [(set (match_operand:SI 0 "s_register_operand") + (match_operator 1 "" [(match_operand 2 "") + (match_operand 3 "")]))] + "TARGET_32BIT" +"{ + enum machine_mode mode = GET_MODE (operands[2]); + if (mode != CCmode) + { + operands[2] = gen_rtx_REG (CCmode, CC_REGNUM); + operands[3] = const0_rtx; + operands[1] = gen_rtx_fmt_ee (arm_ccmode_to_code (mode), + SImode, operands[2], operands[3]); + } + emit_insn (gen_rtx_SET (SImode, operands[0], operands[1])); + DONE; +}") + +;; The first compare in this pattern is the result of a previous CCMP. +;; We can not swap it. And we only need its flag. +(define_insn "*ccmp_and" + [(set (match_operand 6 "dominant_cc_register" "") + (compare + (and:SI + (match_operator 4 "expandable_comparison_operator" + [(match_operand 0 "dominant_cc_register" "") + (match_operand:SI 1 "arm_add_operand" "")]) + (match_operator:SI 5 "arm_comparison_operator" + [(match_operand:SI 2 "s_register_operand" + "l,r,r,r,r") + (match_operand:SI 3 "arm_add_operand" + "lPy,rI,L,rI,L")])) + (const_int 0)))] + "TARGET_32BIT" + { + static const char *const cmp2[2] = + { + "cmp%d4\t%2, %3", + "cmn%d4\t%2, #%n3" + }; + static const char *const ite = "it\t%d4"; + static const int cmp_idx[5] = {0, 0, 1, 0, 1}; + + if (TARGET_THUMB2) + output_asm_insn (ite, operands); + + output_asm_insn (cmp2[cmp_idx[which_alternative]], operands); + return ""; + } + [(set_attr "conds" "set") + (set_attr "predicable" "no") + (set_attr "arch" "t2,t2,t2,any,any") + (set_attr_alternative "length" + [(const_int 4) + (const_int 6) + (const_int 6) + (if_then_else (eq_attr "is_thumb" "no") + (const_int 4) + (const_int 6)) + (if_then_else (eq_attr "is_thumb" "no") + (const_int 4) + (const_int 6))])] +) + +;; The first compare in this pattern is the result of a previous CCMP. +;; We can not swap it. And we only need its flag. +(define_insn "*ccmp_ior" + [(set (match_operand 6 "dominant_cc_register" "") + (compare + (ior:SI + (match_operator 4 "expandable_comparison_operator" + [(match_operand 0 "dominant_cc_register" "") + (match_operand:SI 1 "arm_add_operand" "")]) + (match_operator:SI 5 "arm_comparison_operator" + [(match_operand:SI 2 "s_register_operand" + "l,r,r,r,r") + (match_operand:SI 3 "arm_add_operand" + "lPy,rI,L,rI,L")])) + (const_int 0)))] + "TARGET_32BIT" + { + static const char *const cmp2[2] = + { + "cmp%D4\t%2, %3", + "cmn%D4\t%2, #%n3" + }; + static const char *const ite = "it\t%D4"; + static const int cmp_idx[5] = {0, 0, 1, 0, 1}; + + if (TARGET_THUMB2) + output_asm_insn (ite, operands); + + output_asm_insn (cmp2[cmp_idx[which_alternative]], operands); + return ""; + } + [(set_attr "conds" "set") + (set_attr "arch" "t2,t2,t2,any,any") + (set_attr_alternative "length" + [(const_int 4) + (const_int 6) + (const_int 6) + (if_then_else (eq_attr "is_thumb" "no") + (const_int 4) + (const_int 6)) + (if_then_else (eq_attr "is_thumb" "no") + (const_int 4) + (const_int 6))])] +)