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: 323510 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 76A482C0212 for ; Mon, 24 Feb 2014 20:18:29 +1100 (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:cc:content-type; q=dns; s=default; b=GrJpAPKlCFzFgrW6gChUkwOjdeJVFyzTvBFsDqUeq1L JACUQk+o/Hy32ReW2XBDM+MixtfpedIwrsjmFrJyCY80I/sd7MmGWWnkeinJ9xLy 7pPabmOjV4H8F7osDai1Z2TMpEc2K9aU/fEIGjgsyZR32us+iL2KBXA6AITpfNuY = 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:cc:content-type; s=default; bh=TjCWKiKoHJTkcVr30FKRkXn8Tog=; b=mWLMfY0NS5tFUqN4s sRzEo5KH6paCwDkSB1AJZAtZ0UeYx7boCrUxhuW+Dh4l1ndapElT2azu1qcCr0KX VOOQZhGixsVUXuFh6SqgQhUPJgj9JG0TdaOzT+7RdBH78jyzjH6MvyLmM/OJE5hp TfJ6QPLd99/qFUb2KvJk8x6EPs= Received: (qmail 12775 invoked by alias); 24 Feb 2014 09:18:22 -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 12762 invoked by uid 89); 24 Feb 2014 09:18:21 -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-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) 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:cc :content-type; bh=NrcvTctVuBuEBC4+JiVbf0crUteq3eaA9P2SDgklBqQ=; b=Lyrm92k3RsPVoA8urnc0wtEA+7AZVetJeGitGUL7zAODCmu7T52o2SplpgP8RzQgGw DRSUvoD4KSAKKf/QMO5H7TWRTq3x7WiVcn3144j5rWO9QmE9dXdqEmYBWeELAQSDFV2d ChOWS+c9x4F+st6k7hNaxS5nMq+Sf3PHOpO/lKOdPJonhurS6HDXB9taWaGY0RGnXNqA 9t0M4mfABOs67sPgTNHjJq/IYLXpXeZXmOTbefx+VocWRJ/TRZ8AmGc0ewRxjnHD/ASz EtY5l4xdJwjzEl748s1DSzguv1muQIFELLwhOjr0mmIE/OSsbl3vfOTgusSAcSzWF++0 /BwQ== X-Gm-Message-State: ALoCoQlaJWHReHzkTDPMBK/mYaFNl1I+epIkl1+qGYicmnQdlZUWEiyZKVhezrq/uYMj46jAwxzH 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 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))])] +)