From patchwork Fri Oct 18 19:48:48 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: 176958 Delivered-To: patch@linaro.org Received: by 2002:ac9:3c86:0:0:0:0:0 with SMTP id w6csp1294400ocf; Fri, 18 Oct 2019 12:57:47 -0700 (PDT) X-Google-Smtp-Source: APXvYqw/15MdQqiSCc6q34u/xlUzhKrxrB6I2HewJF/k+NQurHnHZzk06QQgrLo5jn8LOsk+MaES X-Received: by 2002:a50:fd16:: with SMTP id i22mr11501512eds.154.1571428667765; Fri, 18 Oct 2019 12:57:47 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1571428667; cv=none; d=google.com; s=arc-20160816; b=oPus5IHhZD8bAH04woejZ8M0W1PMuh3L5Tyn2Cy2alyiXJeaqch/Ku45QioGp034Lp KTNrIPJ0/596Xo5Zf96ZJQ13p1aiOqWPBVVB8ogMObVowPlwF3fi46adioNpnOKdKUpE nGfd1605/a1OHyRHgehgtgtKyddPu4U5BUNx8y9FPDrTsEdLhtgBf7KnAObSVb18Q5pg gF7bXsNFhkP2cVm1snLPF8w1U8NNmw7KOMCEqJnoA5bEaodhtmHFwl6hWGm1g+EJpm/I OT30v9gXJK3Eazsqx9uawLdCAKPIt8TuYh8wOgDuJ5UfxOk5bOZOqG1fU+V6ttZif35c CHuA== 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=hgBXHtp2dBWAHphHAs7TxGEcaYAopMkFks5uMtskoQM=; b=zTGwM/k+igNsU56dzcHq5Vx+GW7R7hFihU2tVZuPETCFcCf6cDxSd8iaK4kA8LpzmO Yffa5UeQcJJnYKvZSe/NXOlHTvnkeEVNj+A1JqgAhF7GPA7eKZFJY9jKn/1wYzrqT+x8 bV/JNNoIzrlXwzo0kvZ9tOQsc2e1+7eUvlVgQp0oCsSQqzJ0exchHSMFv/mubw2cN98O CPhOjtMtenK5E6WXKEi6tlfPbJchJ1yMorpCW9D1dkvDr+Ph6oYklnO+Q2Zes6v4fWet HPUS8rarFfztmW8456LVvSMA37kjxY04ZUicwV3QMXSqYAq41a+1FQ6+rvH+AQjK1ySd ZINw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gcc.gnu.org header.s=default header.b=cuL6Q4F0; spf=pass (google.com: domain of gcc-patches-return-511324-patch=linaro.org@gcc.gnu.org designates 209.132.180.131 as permitted sender) smtp.mailfrom="gcc-patches-return-511324-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 s27si4580503edm.226.2019.10.18.12.57.46 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 18 Oct 2019 12:57:47 -0700 (PDT) Received-SPF: pass (google.com: domain of gcc-patches-return-511324-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=cuL6Q4F0; spf=pass (google.com: domain of gcc-patches-return-511324-patch=linaro.org@gcc.gnu.org designates 209.132.180.131 as permitted sender) smtp.mailfrom="gcc-patches-return-511324-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=NOyX/0XK79RjMsFm wKB11l87I1WzB4wIa+1JViFlpKpEefhKNIx4l0y3P8kaDO8BVVYV+00D8YTfhg0i Bz2YfsTGeQW8sJBdcwZUuXVoyCscbDGauE07dgiBAxoJtq49Q80MIA5j4okEHM5V jdnLC+6hwFUOPt0hgGRl58GvnZA= 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=s3L8B4ch5HlmqIfqaZZS5w 153W4=; b=cuL6Q4F0YqHvW4HxHCbk/36WduREtu5Y6xaur9vGzqjvfyScfm5LMD 0YtvfmxAzPWFt4bYfI45kmcl1gEaHEl8+mSB/xrkTleb2pVB/RxMh7NxntGyzO9Z z0eje0FobL3HUpsha5e/ffGJEiWn5wLKm4nkP/BDYG5MT+koejzQM= Received: (qmail 114929 invoked by alias); 18 Oct 2019 19:55: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 113307 invoked by uid 89); 18 Oct 2019 19:55:41 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-18.9 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, SPF_FAIL autolearn=ham version=3.3.1 spammy=swapped X-HELO: eggs.gnu.org Received: from eggs.gnu.org (HELO eggs.gnu.org) (209.51.188.92) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Fri, 18 Oct 2019 19:55:39 +0000 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iLYLS-00055e-NK for gcc-patches@gcc.gnu.org; Fri, 18 Oct 2019 15:55:32 -0400 Received: from [217.140.110.172] (port=42740 helo=foss.arm.com) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1iLYLS-00053X-Es for gcc-patches@gcc.gnu.org; Fri, 18 Oct 2019 15:55:30 -0400 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 213631715; Fri, 18 Oct 2019 12:49:24 -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 A2CC23F6C4; Fri, 18 Oct 2019 12:49:23 -0700 (PDT) From: Richard Earnshaw To: gcc-patches@gcc.gnu.org Cc: Richard Earnshaw Subject: [PATCH 17/29] [arm] Handle some constant comparisons using rsbs+rscs Date: Fri, 18 Oct 2019 20:48:48 +0100 Message-Id: <20191018194900.34795-18-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 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 217.140.110.172 In a small number of cases it is preferable to handle comparisons with constants using the sequence RSBS tmp, Xlo, constlo RSCS tmp, Xhi, consthi which allows us to handle a small number of LE/GT/LEU/GEU cases when changing the code to use LT/GE/LTU/GEU would make the constant more expensive. Sadly, we cannot do this on Thumb, since we need RSC, so we now always use the incremented constant in that case since normally that still works out cheaper than forcing the entire constant into a register. Further investigation has also shown that the canonicalization of a reverse subtract and compare is valid for signed as well as unsigned value, so we relax the restriction on selecting CC_RSBmode to allow all types of compare. * config/arm/arm.c (arm_const_double_prefer_rsbs_rsc): New function. (arm_canonicalize_comparison): For GT/LE/GTU/GEU, use the constant unchanged only if that will be cheaper. (arm_select_cc_mode): Recognize a swapped comparison that will be regenerated using RSBS or RSCS. Relax restriction on selecting CC_RSBmode. (arm_gen_dicompare_reg): Handle LE/GT/LEU/GEU comparisons against a constant. (arm_gen_compare_reg): Handle compare (CONST, X) when the mode is CC_RSBmode. (maybe_get_arm_condition_code): CC_RSBmode now returns the same codes as CCmode. * config/arm/arm.md (rsb_imm_compare_scratch): New pattern. (rscsi3_out_scratch): New pattern. --- gcc/config/arm/arm.c | 153 +++++++++++++++++++++++++++++------------- gcc/config/arm/arm.md | 27 ++++++++ 2 files changed, 134 insertions(+), 46 deletions(-) diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c index 99c8bd79d30..299dce638c2 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -5355,6 +5355,21 @@ arm_gen_constant (enum rtx_code code, machine_mode mode, rtx cond, return insns; } +/* Return TRUE if op is a constant where both the low and top words are + suitable for RSB/RSC instructions. This is never true for Thumb, since + we do not have RSC in that case. */ +static bool +arm_const_double_prefer_rsbs_rsc (rtx op) +{ + /* Thumb lacks RSC, so we never prefer that sequence. */ + if (TARGET_THUMB || !CONST_INT_P (op)) + return false; + HOST_WIDE_INT hi, lo; + lo = UINTVAL (op) & 0xffffffffULL; + hi = UINTVAL (op) >> 32; + return const_ok_for_arm (lo) && const_ok_for_arm (hi); +} + /* Canonicalize a comparison so that we are more likely to recognize it. This can be done for a few constant compares, where we can make the immediate value easier to load. */ @@ -5380,8 +5395,7 @@ arm_canonicalize_comparison (int *code, rtx *op0, rtx *op1, { if (*code == GT || *code == LE - || ((!TARGET_ARM || CONST_INT_P (*op1)) - && (*code == GTU || *code == LEU))) + || *code == GTU || *code == LEU) { /* Missing comparison. First try to use an available comparison. */ @@ -5392,10 +5406,13 @@ arm_canonicalize_comparison (int *code, rtx *op0, rtx *op1, { case GT: case LE: - if (i != maxval - && (!arm_const_double_by_immediates (*op1) - || arm_const_double_by_immediates (GEN_INT (i + 1)))) + if (i != maxval) { + /* Try to convert to GE/LT, unless that would be more + expensive. */ + if (!arm_const_double_by_immediates (GEN_INT (i + 1)) + && arm_const_double_prefer_rsbs_rsc (*op1)) + return; *op1 = GEN_INT (i + 1); *code = *code == GT ? GE : LT; return; @@ -5404,10 +5421,13 @@ arm_canonicalize_comparison (int *code, rtx *op0, rtx *op1, case GTU: case LEU: - if (i != ~((unsigned HOST_WIDE_INT) 0) - && (!arm_const_double_by_immediates (*op1) - || arm_const_double_by_immediates (GEN_INT (i + 1)))) + if (i != ~((unsigned HOST_WIDE_INT) 0)) { + /* Try to convert to GEU/LTU, unless that would + be more expensive. */ + if (!arm_const_double_by_immediates (GEN_INT (i + 1)) + && arm_const_double_prefer_rsbs_rsc (*op1)) + return; *op1 = GEN_INT (i + 1); *code = *code == GTU ? GEU : LTU; return; @@ -5419,7 +5439,6 @@ arm_canonicalize_comparison (int *code, rtx *op0, rtx *op1, } } - /* If that did not work, reverse the condition. */ if (!op0_preserve_value) { std::swap (*op0, *op1); @@ -15251,6 +15270,28 @@ arm_select_cc_mode (enum rtx_code op, rtx x, rtx y) || GET_CODE (x) == ROTATERT)) return CC_SWPmode; + /* A widened compare of the sum of a value plus a carry against a + constant. This is a representation of RSC. We want to swap the + result of the comparison at output. Not valid if the Z bit is + needed. */ + if (GET_MODE (x) == DImode + && GET_CODE (x) == PLUS + && arm_borrow_operation (XEXP (x, 1), DImode) + && CONST_INT_P (y) + && ((GET_CODE (XEXP (x, 0)) == SIGN_EXTEND + && (op == LE || op == GT)) + || (GET_CODE (XEXP (x, 0)) == ZERO_EXTEND + && (op == LEU || op == GTU)))) + return CC_SWPmode; + + /* If X is a constant we want to use CC_RSBmode. This is + non-canonical, but arm_gen_compare_reg uses this to generate the + correct canonical form. */ + if (GET_MODE (y) == SImode + && (REG_P (y) || GET_CODE (y) == SUBREG) + && CONST_INT_P (x)) + return CC_RSBmode; + /* This operation is performed swapped, but since we only rely on the Z flag we don't need an additional mode. */ if (GET_MODE (y) == SImode @@ -15329,15 +15370,13 @@ arm_select_cc_mode (enum rtx_code op, rtx x, rtx y) || (TARGET_32BIT && GET_CODE (x) == ZERO_EXTRACT))) return CC_NOOVmode; - /* An unsigned comparison of ~reg with a const is really a special + /* A comparison of ~reg with a const is really a special canoncialization of compare (~const, reg), which is a reverse subtract operation. We may not get here if CONST is 0, but that doesn't matter because ~0 isn't a valid immediate for RSB. */ if (GET_MODE (x) == SImode && GET_CODE (x) == NOT - && CONST_INT_P (y) - && (op == EQ || op == NE - || op == LTU || op == LEU || op == GEU || op == GTU)) + && CONST_INT_P (y)) return CC_RSBmode; if (GET_MODE (x) == QImode && (op == EQ || op == NE)) @@ -15431,6 +15470,7 @@ 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. */ gcc_assert (TARGET_32BIT); + gcc_assert (!CONST_INT_P (x)); rtx x_lo = simplify_gen_subreg (SImode, x, DImode, subreg_lowpart_offset (SImode, DImode)); @@ -15445,9 +15485,6 @@ arm_gen_dicompare_reg (rtx_code code, rtx x, rtx y, rtx scratch) 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) @@ -15525,10 +15562,6 @@ arm_gen_dicompare_reg (rtx_code code, rtx x, rtx y, rtx scratch) 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), @@ -15536,13 +15569,10 @@ arm_gen_dicompare_reg (rtx_code code, rtx x, rtx y, rtx scratch) 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, @@ -15556,6 +15586,27 @@ arm_gen_dicompare_reg (rtx_code code, rtx x, rtx y, rtx scratch) return SET_DEST (single_set (insn)); } + case LE: + case GT: + { + /* During expansion, we only expect to get here if y is a + constant that we want to handle, otherwise we should have + swapped the operands already. */ + gcc_assert (arm_const_double_prefer_rsbs_rsc (y)); + + if (!const_ok_for_arm (INTVAL (y_lo))) + y_lo = force_reg (SImode, y_lo); + + /* Perform a reverse subtract and compare. */ + rtx cmp1 + = gen_rtx_LTU (DImode, + arm_gen_compare_reg (LTU, y_lo, x_lo, scratch), + const0_rtx); + rtx_insn *insn = emit_insn (gen_rscsi3_CC_NVout_scratch (scratch, y_hi, + x_hi, cmp1)); + return SET_DEST (single_set (insn)); + } + case LTU: case GEU: { @@ -15572,10 +15623,6 @@ arm_gen_dicompare_reg (rtx_code code, rtx x, rtx y, rtx scratch) 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), @@ -15586,10 +15633,6 @@ arm_gen_dicompare_reg (rtx_code code, rtx x, rtx y, rtx scratch) 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, @@ -15607,6 +15650,28 @@ arm_gen_dicompare_reg (rtx_code code, rtx x, rtx y, rtx scratch) return SET_DEST (single_set (insn)); } + case LEU: + case GTU: + { + /* During expansion, we only expect to get here if y is a + constant that we want to handle, otherwise we should have + swapped the operands already. */ + gcc_assert (arm_const_double_prefer_rsbs_rsc (y)); + + if (!const_ok_for_arm (INTVAL (y_lo))) + y_lo = force_reg (SImode, y_lo); + + /* Perform a reverse subtract and compare. */ + rtx cmp1 + = gen_rtx_LTU (DImode, + arm_gen_compare_reg (LTU, y_lo, x_lo, scratch), + const0_rtx); + y_hi = GEN_INT (0xffffffff & UINTVAL (y_hi)); + rtx_insn *insn = emit_insn (gen_rscsi3_CC_Bout_scratch (scratch, y_hi, + x_hi, cmp1)); + return SET_DEST (single_set (insn)); + } + default: break; } @@ -15695,8 +15760,15 @@ arm_gen_compare_reg (rtx_code code, rtx x, rtx y, rtx scratch) machine_mode mode = SELECT_CC_MODE (code, x, y); rtx cc_reg = gen_rtx_REG (mode, CC_REGNUM); - - emit_set_insn (cc_reg, gen_rtx_COMPARE (mode, x, y)); + if (mode == CC_RSBmode) + { + if (!scratch) + scratch = gen_rtx_SCRATCH (SImode); + emit_insn (gen_rsb_imm_compare_scratch (scratch, + GEN_INT (~UINTVAL (x)), y)); + } + else + emit_set_insn (cc_reg, gen_rtx_COMPARE (mode, x, y)); return cc_reg; } @@ -24025,19 +24097,8 @@ maybe_get_arm_condition_code (rtx comparison) default: return ARM_NV; } - case E_CC_RSBmode: - switch (comp_code) - { - case NE: return ARM_NE; - case EQ: return ARM_EQ; - case GEU: return ARM_CS; - case GTU: return ARM_HI; - case LEU: return ARM_LS; - case LTU: return ARM_CC; - default: return ARM_NV; - } - case E_CCmode: + case E_CC_RSBmode: switch (comp_code) { case NE: return ARM_NE; diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md index f0ff4dda396..8607c6f95da 100644 --- a/gcc/config/arm/arm.md +++ b/gcc/config/arm/arm.md @@ -1363,6 +1363,33 @@ (define_insn "rsb_imm_compare" (set_attr "type" "alus_imm")] ) +;; Similarly, but the result is unused. +(define_insn "rsb_imm_compare_scratch" + [(set (reg:CC_RSB CC_REGNUM) + (compare:CC_RSB (not:SI (match_operand:SI 2 "s_register_operand" "r")) + (match_operand 1 "arm_not_immediate_operand" "K"))) + (clobber (match_scratch:SI 0 "=r"))] + "TARGET_32BIT" + "rsbs\\t%0, %2, #%B1" + [(set_attr "conds" "set") + (set_attr "type" "alus_imm")] +) + +;; Compare the sum of a value plus a carry against a constant. Uses +;; RSC, so the result is swapped. Only available on Arm +(define_insn "rscsi3_out_scratch" + [(set (reg:CC_SWP CC_REGNUM) + (compare:CC_SWP + (plus:DI (SE:DI (match_operand:SI 2 "s_register_operand" "r")) + (match_operand:DI 3 "arm_borrow_operation" "")) + (match_operand 1 "arm_immediate_operand" "I"))) + (clobber (match_scratch:SI 0 "=r"))] + "TARGET_ARM" + "rscs\\t%0, %2, %1" + [(set_attr "conds" "set") + (set_attr "type" "alus_imm")] +) + (define_expand "subsf3" [(set (match_operand:SF 0 "s_register_operand") (minus:SF (match_operand:SF 1 "s_register_operand")