From patchwork Fri Oct 18 19:48:47 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Richard Earnshaw \(lists\)" X-Patchwork-Id: 176948 Delivered-To: patch@linaro.org Received: by 2002:ac9:3c86:0:0:0:0:0 with SMTP id w6csp1288320ocf; Fri, 18 Oct 2019 12:51:06 -0700 (PDT) X-Google-Smtp-Source: APXvYqx2T7J+SdTeaVWB+NUZwrFsnv6DutWqz8iyxBRiiDeszJ3VsyaVOGZ9LR2H2JcpqPkRVxFZ X-Received: by 2002:a17:906:d214:: with SMTP id w20mr10269927ejz.68.1571428266180; Fri, 18 Oct 2019 12:51:06 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1571428266; cv=none; d=google.com; s=arc-20160816; b=sw5MI0LWhHFgT9TD0J1y/EuZt0LrHkTa5CTA3kG76qVM86IXqxZYNDkkGV3lzzUq64 s5AjFXuF+HfQxyyxgS6PqiCPSv+bv3fwHe2LBFEjOvtScyXkF3Bjb2FezQDhdMoEW8XN qm7UkEbjptStc51WBo9LW7ZHUIwjccjvYwLLyXxyFAWdtuo0NkVHd/XbIIJ9IP7y6mwC ozBWVQwZTIno3m7RZj2F1hkVEfnkZDHRK86SxMDQNoaHT4MPmh5ZrYbrM8WGlYcLHECm nAHee7oEs094kGDpzMMbU58W8UCfUk38FTetyMOk823LFIWCCHxm04XU496jdq6XSBeZ nStQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=mime-version:references:in-reply-to:message-id:date:subject:cc:to :from:delivered-to:sender:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:mailing-list:dkim-signature :domainkey-signature; bh=i0Af+p9A6shDg3JPsbm0LfgPN0s2Pv/zqAnpxR8Rp+w=; b=XIGyhCxZL2n/NOyPjz/nh+PpA2UZQU7cNCXU/n8pS7e0F1y/StUrXUwtK8tng7cCNz Cpkx1uS6/KKOnxvqVUXC0wiAI0Yu/ASrVdUc1f1V9WNHEl8zGaJa2yatvIqhcOr4YKji L1I+0m/F0XWHa208rs36jUFY3N+Urg3mx3GxemJtkoFoc6Esq36h6JMmBi7U2FLgo2Zs 3Ygdm31UtllJZaQHEZMvx9qmGsb3Iw8znRE2/uP0Jcc2TeNJWM7VEl5txbuzs9EC2s9k kuCI4U8YtOYv0ndkmzoaYYLUMbJvuRKrqgampLzvF3WYXr+VskDFkMRUduGuJ+qhlDGi hGUg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gcc.gnu.org header.s=default header.b=cpSdeyRm; spf=pass (google.com: domain of gcc-patches-return-511314-patch=linaro.org@gcc.gnu.org designates 209.132.180.131 as permitted sender) smtp.mailfrom="gcc-patches-return-511314-patch=linaro.org@gcc.gnu.org" Return-Path: Received: from sourceware.org (server1.sourceware.org. [209.132.180.131]) by mx.google.com with ESMTPS id q7si67330edi.103.2019.10.18.12.51.05 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 18 Oct 2019 12:51:06 -0700 (PDT) Received-SPF: pass (google.com: domain of gcc-patches-return-511314-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; dkim=pass header.i=@gcc.gnu.org header.s=default header.b=cpSdeyRm; spf=pass (google.com: domain of gcc-patches-return-511314-patch=linaro.org@gcc.gnu.org designates 209.132.180.131 as permitted sender) smtp.mailfrom="gcc-patches-return-511314-patch=linaro.org@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:from :to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-type; q=dns; s=default; b=lORn292cjq6VN7p3 c7JR6nmM6H90z2P+YQhyRTYTGneHTyZldHXV+YCawNW828kTCXP3eDVxx7UGpIj0 Sx/xDmQQaCDeMwqqIPKjfg2baP0P//gyBwg7yalEnuv0JjE29VzPc7pWQO2Xxr8L B5vOZuUjWsoCrdNu15rTlKUaMCg= 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:from :to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-type; s=default; bh=9VWjUBXlwoFa0m7SubCTw2 U2By8=; b=cpSdeyRmeqjJ9FPFXtXyA+BBEWWeYhbw23NgQwSi58QXDnCfxbVS37 3Pt6F5QtlehXyr0biZz5B3/vTmuW7m81QGQLCRnNg38NiRFyj5Z3UDFT1Gqf0bNl HWPMd1B/oIS4t2IUVXe0GeJCit3Bx64AMArNbBhR1I7TakbRaja0c= Received: (qmail 78553 invoked by alias); 18 Oct 2019 19:49:41 -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 78452 invoked by uid 89); 18 Oct 2019 19:49:40 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-18.5 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, SPF_PASS autolearn=ham version=3.3.1 spammy=sk:adjust_ X-HELO: foss.arm.com Received: from Unknown (HELO foss.arm.com) (217.140.110.172) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Fri, 18 Oct 2019 19:49:37 +0000 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 6DA9716F8; Fri, 18 Oct 2019 12:49:23 -0700 (PDT) Received: from eagle.buzzard.freeserve.co.uk (unknown [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id EF3333F6C4; Fri, 18 Oct 2019 12:49:22 -0700 (PDT) From: Richard Earnshaw To: gcc-patches@gcc.gnu.org Cc: Richard Earnshaw Subject: [PATCH 16/29] [arm] early split most DImode comparison operations. Date: Fri, 18 Oct 2019 20:48:47 +0100 Message-Id: <20191018194900.34795-17-Richard.Earnshaw@arm.com> In-Reply-To: <20191018194900.34795-1-Richard.Earnshaw@arm.com> References: <20191018194900.34795-1-Richard.Earnshaw@arm.com> MIME-Version: 1.0 This patch does most of the work for early splitting the DImode comparisons. We now handle EQ, NE, LT, GE, LTU and GEU during early expansion, in addition to EQ and NE, for which the expansion has now been reworked to use a standard conditional-compare pattern already in the back-end. To handle this we introduce two new condition flag modes that are used when comparing the upper words of decomposed DImode values: one for signed, and one for unsigned comparisons. CC_Bmode (B for Borrow) is essentially the inverse of CC_Cmode and is used when the carry flag is set by a subtraction of unsigned values. * config/arm/arm-modes.def (CC_NV, CC_B): New CC modes. * config/arm/arm.c (arm_select_cc_mode): Recognize constructs that need these modes. (arm_gen_dicompare_reg): New code to early expand the sub-operations of EQ, NE, LT, GE, LTU and GEU. * config/arm/iterators.md (CC_EXTEND): New code attribute. * config/arm/predicates.md (arm_adcimm_operand): New predicate.. * config/arm/arm.md (cmpsi3_carryin_out): New pattern. (cmpsi3_imm_carryin_out): Likewise. (cmpsi3_0_carryin_out): Likewise. --- gcc/config/arm/arm-modes.def | 6 + gcc/config/arm/arm.c | 220 ++++++++++++++++++++++++++++++++++- gcc/config/arm/arm.md | 45 +++++++ gcc/config/arm/iterators.md | 4 + gcc/config/arm/predicates.md | 6 + 5 files changed, 278 insertions(+), 3 deletions(-) diff --git a/gcc/config/arm/arm-modes.def b/gcc/config/arm/arm-modes.def index 4fa7f1b43e5..65cddf68cdb 100644 --- a/gcc/config/arm/arm-modes.def +++ b/gcc/config/arm/arm-modes.def @@ -34,12 +34,16 @@ ADJUST_FLOAT_FORMAT (HF, ((arm_fp16_format == ARM_FP16_FORMAT_ALTERNATIVE) CC_Cmode should be used if only the C flag is set correctly, after an addition. CC_Nmode should be used if only the N (sign) flag is set correctly + CC_NVmode should be used if only the N and V bits are set correctly, + (used for signed comparisons when the carry is propagated in). CC_CZmode should be used if only the C and Z flags are correct (used for DImode unsigned comparisons). CC_RSBmode should be used where the comparison is set by an RSB immediate, or NEG instruction. The form of the comparison for (const - reg) will be (COMPARE (not (reg)) (~const)). CC_NCVmode should be used if only the N, C, and V flags are correct + CC_Bmode should be used if only the C flag is correct after a subtract + (eg after an unsigned borrow with carry-in propagation). (used for DImode signed comparisons). CCmode should be used otherwise. */ @@ -47,6 +51,7 @@ CC_MODE (CC_NOOV); CC_MODE (CC_Z); CC_MODE (CC_CZ); CC_MODE (CC_NCV); +CC_MODE (CC_NV); CC_MODE (CC_SWP); CC_MODE (CC_RSB); CC_MODE (CCFP); @@ -62,6 +67,7 @@ CC_MODE (CC_DLTU); CC_MODE (CC_DGEU); CC_MODE (CC_DGTU); CC_MODE (CC_C); +CC_MODE (CC_B); CC_MODE (CC_N); CC_MODE (CC_V); diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c index ddfe4335169..99c8bd79d30 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -15348,6 +15348,22 @@ arm_select_cc_mode (enum rtx_code op, rtx x, rtx y) && (rtx_equal_p (XEXP (x, 0), y) || rtx_equal_p (XEXP (x, 1), y))) return CC_Cmode; + if (GET_MODE (x) == DImode + && (op == GE || op == LT) + && GET_CODE (x) == SIGN_EXTEND + && ((GET_CODE (y) == PLUS + && arm_borrow_operation (XEXP (y, 0), DImode)) + || arm_borrow_operation (y, DImode))) + return CC_NVmode; + + if (GET_MODE (x) == DImode + && (op == GEU || op == LTU) + && GET_CODE (x) == ZERO_EXTEND + && ((GET_CODE (y) == PLUS + && arm_borrow_operation (XEXP (y, 0), DImode)) + || arm_borrow_operation (y, DImode))) + return CC_Bmode; + if (GET_MODE (x) == DImode || GET_MODE (y) == DImode) { switch (op) @@ -15410,16 +15426,198 @@ arm_select_cc_mode (enum rtx_code op, rtx x, rtx y) static rtx arm_gen_dicompare_reg (rtx_code code, rtx x, rtx y, rtx scratch) { - /* We don't currently handle DImode in thumb1, but rely on libgcc. */ + machine_mode mode; + rtx cc_reg; + + /* We don't currently handle DImode in thumb1, but rely on libgcc. */ gcc_assert (TARGET_32BIT); + rtx x_lo = simplify_gen_subreg (SImode, x, DImode, + subreg_lowpart_offset (SImode, DImode)); + rtx x_hi = simplify_gen_subreg (SImode, x, DImode, + subreg_highpart_offset (SImode, DImode)); + rtx y_lo = simplify_gen_subreg (SImode, y, DImode, + subreg_lowpart_offset (SImode, DImode)); + rtx y_hi = simplify_gen_subreg (SImode, y, DImode, + subreg_highpart_offset (SImode, DImode)); + switch (code) + { + case EQ: + case NE: + { + /* We should never have X as a const_int in this case. */ + gcc_assert (!CONST_INT_P (x)); + + if (y_lo == const0_rtx || y_hi == const0_rtx) + { + if (y_lo != const0_rtx) + { + rtx scratch2 = scratch ? scratch : gen_reg_rtx (SImode); + + gcc_assert (y_hi == const0_rtx); + y_lo = gen_int_mode (-INTVAL (y_lo), SImode); + if (!arm_add_operand (y_lo, SImode)) + y_lo = force_reg (SImode, y_lo); + emit_insn (gen_addsi3 (scratch2, x_lo, y_lo)); + x_lo = scratch2; + } + else if (y_hi != const0_rtx) + { + rtx scratch2 = scratch ? scratch : gen_reg_rtx (SImode); + + y_hi = gen_int_mode (-INTVAL (y_hi), SImode); + if (!arm_add_operand (y_hi, SImode)) + y_hi = force_reg (SImode, y_hi); + emit_insn (gen_addsi3 (scratch2, x_hi, y_hi)); + x_hi = scratch2; + } + + if (!scratch) + { + gcc_assert (!reload_completed); + scratch = gen_rtx_SCRATCH (SImode); + } + + rtx clobber = gen_rtx_CLOBBER (VOIDmode, scratch); + cc_reg = gen_rtx_REG (CC_NOOVmode, CC_REGNUM); + + rtx set + = gen_rtx_SET (cc_reg, + gen_rtx_COMPARE (CC_NOOVmode, + gen_rtx_IOR (SImode, x_lo, x_hi), + const0_rtx)); + emit_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, set, + clobber))); + return cc_reg; + } + + if (!arm_add_operand (y_lo, SImode)) + y_lo = force_reg (SImode, y_lo); + + if (!arm_add_operand (y_hi, SImode)) + y_hi = force_reg (SImode, y_hi); + + rtx cmp1 = gen_rtx_NE (SImode, x_lo, y_lo); + rtx cmp2 = gen_rtx_NE (SImode, x_hi, y_hi); + rtx conjunction = gen_rtx_IOR (SImode, cmp1, cmp2); + mode = SELECT_CC_MODE (code, conjunction, const0_rtx); + cc_reg = gen_rtx_REG (mode, CC_REGNUM); + + emit_insn (gen_rtx_SET (cc_reg, + gen_rtx_COMPARE (VOIDmode, conjunction, + const0_rtx))); + return cc_reg; + } + + case LT: + case GE: + { + if (y_lo == const0_rtx) + { + /* If the low word of y is 0, then this is simply a normal + compare of the upper words. */ + if (!arm_add_operand (y_hi, SImode)) + y_hi = force_reg (SImode, y_hi); + + return arm_gen_compare_reg (code, x_hi, y_hi, NULL_RTX); + } + + if (!arm_add_operand (y_lo, SImode)) + y_lo = force_reg (SImode, y_lo); + + /* Just for now. */ + if (!register_operand (x_lo, SImode)) + x_lo = force_reg (SImode, x_lo); + + rtx cmp1 + = gen_rtx_LTU (DImode, + arm_gen_compare_reg (LTU, x_lo, y_lo, NULL_RTX), + const0_rtx); + + if (!scratch) + scratch = gen_rtx_SCRATCH (SImode); + if (!arm_not_operand (y_hi, SImode)) + y_hi = force_reg (SImode, y_hi); + + /* Just for now. */ + if (!register_operand (x_hi, SImode)) + x_hi = force_reg (SImode, x_hi); + + rtx_insn *insn; + if (y_hi == const0_rtx) + insn = emit_insn (gen_cmpsi3_0_carryin_CC_NVout (scratch, x_hi, + cmp1)); + else if (CONST_INT_P (y_hi)) + insn = emit_insn (gen_cmpsi3_imm_carryin_CC_NVout (scratch, x_hi, + y_hi, cmp1)); + else + insn = emit_insn (gen_cmpsi3_carryin_CC_NVout (scratch, x_hi, y_hi, + cmp1)); + return SET_DEST (single_set (insn)); + } + + case LTU: + case GEU: + { + if (y_lo == const0_rtx) + { + /* If the low word of y is 0, then this is simply a normal + compare of the upper words. */ + if (!arm_add_operand (y_hi, SImode)) + y_hi = force_reg (SImode, y_hi); + + return arm_gen_compare_reg (code, x_hi, y_hi, NULL_RTX); + } + + if (!arm_add_operand (y_lo, SImode)) + y_lo = force_reg (SImode, y_lo); + + /* Just for now. */ + if (!register_operand (x_lo, SImode)) + x_lo = force_reg (SImode, x_lo); + + rtx cmp1 + = gen_rtx_LTU (DImode, + arm_gen_compare_reg (LTU, x_lo, y_lo, NULL_RTX), + const0_rtx); + + if (!scratch) + scratch = gen_rtx_SCRATCH (SImode); + if (!arm_not_operand (y_hi, SImode)) + y_hi = force_reg (SImode, y_hi); + + /* Just for now. */ + if (!register_operand (x_hi, SImode)) + x_hi = force_reg (SImode, x_hi); + + rtx_insn *insn; + if (y_hi == const0_rtx) + insn = emit_insn (gen_cmpsi3_0_carryin_CC_Bout (scratch, x_hi, + cmp1)); + else if (CONST_INT_P (y_hi)) + { + /* Constant is viewed as unsigned when zero-extended. */ + y_hi = GEN_INT (UINTVAL (y_hi) & 0xffffffffULL); + insn = emit_insn (gen_cmpsi3_imm_carryin_CC_Bout (scratch, x_hi, + y_hi, cmp1)); + } + else + insn = emit_insn (gen_cmpsi3_carryin_CC_Bout (scratch, x_hi, y_hi, + cmp1)); + return SET_DEST (single_set (insn)); + } + + default: + break; + } + /* We might have X as a constant, Y as a register because of the predicates used for cmpdi. If so, force X to a register here. */ if (!REG_P (x)) x = force_reg (DImode, x); - machine_mode mode = SELECT_CC_MODE (code, x, y); - rtx cc_reg = gen_rtx_REG (mode, CC_REGNUM); + mode = SELECT_CC_MODE (code, x, y); + cc_reg = gen_rtx_REG (mode, CC_REGNUM); if (mode != CC_CZmode) { @@ -23803,6 +24001,22 @@ maybe_get_arm_condition_code (rtx comparison) default: return ARM_NV; } + case E_CC_NVmode: + switch (comp_code) + { + case GE: return ARM_GE; + case LT: return ARM_LT; + default: return ARM_NV; + } + + case E_CC_Bmode: + switch (comp_code) + { + case GEU: return ARM_CS; + case LTU: return ARM_CC; + default: return ARM_NV; + } + case E_CC_Vmode: switch (comp_code) { diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md index 9d8b137651f..f0ff4dda396 100644 --- a/gcc/config/arm/arm.md +++ b/gcc/config/arm/arm.md @@ -1009,6 +1009,51 @@ (define_insn "subsi3_carryin" (set_attr "type" "adc_reg,adc_imm,alu_shift_imm")] ) +(define_insn "cmpsi3_carryin_out" + [(set (reg: CC_REGNUM) + (compare: + (SE:DI (match_operand:SI 1 "s_register_operand" "0,r")) + (plus:DI (match_operand:DI 3 "arm_borrow_operation" "") + (SE:DI (match_operand:SI 2 "s_register_operand" "l,r"))))) + (clobber (match_scratch:SI 0 "=l,r"))] + "TARGET_32BIT" + "sbcs\\t%0, %1, %2" + [(set_attr "conds" "set") + (set_attr "arch" "t2,*") + (set_attr "length" "2,4") + (set_attr "type" "adc_reg")] +) + +;; Similar to the above, but handling a constant which has a different +;; canonicalization. +(define_insn "cmpsi3_imm_carryin_out" + [(set (reg: CC_REGNUM) + (compare: + (SE:DI (match_operand:SI 1 "s_register_operand" "r,r")) + (plus:DI (match_operand:DI 3 "arm_borrow_operation" "") + (match_operand:DI 2 "arm_adcimm_operand" "I,K")))) + (clobber (match_scratch:SI 0 "=l,r"))] + "TARGET_32BIT" + "@ + sbcs\\t%0, %1, %2 + adcs\\t%0, %1, #%B2" + [(set_attr "conds" "set") + (set_attr "type" "adc_imm")] +) + +;; Further canonicalization when the constant is zero. +(define_insn "cmpsi3_0_carryin_out" + [(set (reg: CC_REGNUM) + (compare: + (SE:DI (match_operand:SI 1 "s_register_operand" "r,r")) + (match_operand:DI 2 "arm_borrow_operation" ""))) + (clobber (match_scratch:SI 0 "=l,r"))] + "TARGET_32BIT" + "sbcs\\t%0, %1, #0" + [(set_attr "conds" "set") + (set_attr "type" "adc_imm")] +) + (define_insn "*subsi3_carryin_const" [(set (match_operand:SI 0 "s_register_operand" "=r") (minus:SI (plus:SI diff --git a/gcc/config/arm/iterators.md b/gcc/config/arm/iterators.md index 77e1645083f..5f1c833ad80 100644 --- a/gcc/config/arm/iterators.md +++ b/gcc/config/arm/iterators.md @@ -792,6 +792,10 @@ (define_mode_attr vsi2qi [(V2SI "v8qi") (V4SI "v16qi")]) ;; Code attributes ;;---------------------------------------------------------------------------- +;; Determine the mode of a 'wide compare', ie where the carry flag is +;; propagated into the comparison. +(define_code_attr CC_EXTEND [(sign_extend "CC_NV") (zero_extend "CC_B")]) + ;; Assembler mnemonics for vqh_ops and vqhs_ops iterators. (define_code_attr VQH_mnem [(plus "vadd") (smin "vmin") (smax "vmax") (umin "vmin") (umax "vmax")]) diff --git a/gcc/config/arm/predicates.md b/gcc/config/arm/predicates.md index ed7495b69fc..d9470df8093 100644 --- a/gcc/config/arm/predicates.md +++ b/gcc/config/arm/predicates.md @@ -229,6 +229,12 @@ (define_predicate "arm_not_operand" (ior (match_operand 0 "arm_rhs_operand") (match_operand 0 "arm_not_immediate_operand"))) +;; A constant that can be used with ADC(SBC) or SBC(ADC) when bit-wise +;; inverted. Similar to arm_not_operand, but excludes registers. +(define_predicate "arm_adcimm_operand" + (ior (match_operand 0 "arm_immediate_operand") + (match_operand 0 "arm_not_immediate_operand"))) + (define_predicate "arm_di_operand" (ior (match_operand 0 "s_register_operand") (match_operand 0 "arm_immediate_di_operand")))