From patchwork Fri Oct 18 19:48:37 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: 176967 Delivered-To: patch@linaro.org Received: by 2002:ac9:3c86:0:0:0:0:0 with SMTP id w6csp1296190ocf; Fri, 18 Oct 2019 12:59:47 -0700 (PDT) X-Google-Smtp-Source: APXvYqyObVtVI7cEWeaWXRQt0FYrTBmAvNFyHealVdFVgj/yMD+8V9WkRAN+EE2o+XB+qmrcSfY+ X-Received: by 2002:aa7:dd0f:: with SMTP id i15mr12072394edv.0.1571428787499; Fri, 18 Oct 2019 12:59:47 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1571428787; cv=none; d=google.com; s=arc-20160816; b=vDNGiJIVMhg842dptaftAqn5rhCPlybsHXmXi0yS0igqByRdhM4qrz3i3S/HhdAHIZ ZPa9KoWLvjvYMCBqgjDnybLlDDwMXTRBCmOlIEzqKzlddQc0BMN0iTDiNS7JdTmyZuLB uL19/ywHUg4TJXmaHP8KgC6+piCnJImCt4inqk2QlaCxBsjelVqpn3a+lyvKMudx/f6B TgbWsb6t/JYB8JCr7dRO0Umnfs4fUJIKIUGRRMCDk0/QAnCZYOGFUih6GPxJdXkzlj2+ k9Sv6MW7Z2hbAu7UjvoI+D6OQVXna4YuzYepz0bIBpAwEH2q8J9Gm+y6nBTvX90DRfB4 TxWQ== 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=GPJI6FVbIZt6h6UEN+9KiRL3dKmOWd1WsY5duxXz+Ig=; b=y2Lj3h0pmk1y3x9/udt4pnGcDnwOjp3zgQTC8MyuWare7xaSOgdPhyi3dH9h/p5ufI dCa/U458e0jxPYco8oWa7qo9Du1nrCI0IiBmT/t0O88eiSz9fDJCaS/bgh807qrxSAw3 JUCO+XGefg+jhSrSQYlXHRSPUnbiyeLycCDP35tjG/FneBwG2Lo0dQGeus63vNJG6Ga9 qTnoagV0EU4V5lGwsQxr7TfDzg9ItYwAzhqtfbfwuSwX9v2MDBr0xcQcVoM5eWmJAS12 FazjbAwEWWNeqfZfYieGPJwhgI5YDhzIShuoyF4P5FCwvnjo15AeEUSwuTpv3yHVROJr lYWA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gcc.gnu.org header.s=default header.b=CDwLwT57; spf=pass (google.com: domain of gcc-patches-return-511333-patch=linaro.org@gcc.gnu.org designates 209.132.180.131 as permitted sender) smtp.mailfrom="gcc-patches-return-511333-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 d52si4590486ede.370.2019.10.18.12.59.46 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 18 Oct 2019 12:59:47 -0700 (PDT) Received-SPF: pass (google.com: domain of gcc-patches-return-511333-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=CDwLwT57; spf=pass (google.com: domain of gcc-patches-return-511333-patch=linaro.org@gcc.gnu.org designates 209.132.180.131 as permitted sender) smtp.mailfrom="gcc-patches-return-511333-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=C5eihyWyrLoxwbCB HYHon+WJy6+CGGo+0I6KHgpCtl8zRtUqJIJo+MteM5LqW2j5EA6CkR1xrSXQPYO2 xi+o7Tdf/R5ibqv3+GnSU0CYVM7yM1JlsZVhpQOIKhmxAdQYclqpBymL/A2avHSI 89QVqrtq8xM1dlQgRKUriATskCA= 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=tl/Ry+8YPxoKN9PzqaKmKx 5P1ls=; b=CDwLwT57EHm5tM8L2v5wGDVsLUaYIcn0YlGQvcDfaWUxSJ3n3BPfIB c+hBxgba0AvsGwTFZ69FXZ5EDA3tmDz8pgT2QOQ2yE0OgV+ymZNYRHKAo/3YOdV9 TIy/0xKRmzU9oy5pMthojhV5ITAHgunuEwHqlln37qsdVo6djyS1s= Received: (qmail 118892 invoked by alias); 18 Oct 2019 19:56:15 -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 115560 invoked by uid 89); 18 Oct 2019 19:55:49 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-17.9 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_NUMSUBJECT, SPF_FAIL, UNSUBSCRIBE_BODY autolearn=ham version=3.3.1 spammy= 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:45 +0000 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iLYLd-0005BK-PE for gcc-patches@gcc.gnu.org; Fri, 18 Oct 2019 15:55:43 -0400 Received: from [217.140.110.172] (port=42780 helo=foss.arm.com) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1iLYLd-000568-GV for gcc-patches@gcc.gnu.org; Fri, 18 Oct 2019 15:55:41 -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 8B821161B; Fri, 18 Oct 2019 12:49:16 -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 18DA73F6C4; Fri, 18 Oct 2019 12:49:15 -0700 (PDT) From: Richard Earnshaw To: gcc-patches@gcc.gnu.org Cc: Richard Earnshaw Subject: [PATCH 06/29] [arm] Early split subdi3 Date: Fri, 18 Oct 2019 20:48:37 +0100 Message-Id: <20191018194900.34795-7-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 This patch adds early splitting of subdi3 so that the individual operations can be seen by the optimizers, particuarly combine. This should allow us to do at least as good a job as previously, but with far fewer patterns in the machine description. This is just the initial patch to add the early splitting. The cleanups will follow later. A special trick is used to handle the 'reverse subtract and compare' where a register is subtracted from a constant. The natural comparison (COMPARE (const) (reg)) is not canonical in this case and combine will never correctly generate it (trying to swap the order of the operands. To handle this we write the comparison as (COMPARE (NOT (reg)) (~const)), which has the same result for EQ, NE, LTU, LEU, GTU and GEU, which are all the cases we are really interested in here. Finally, we delete the negdi2 pattern. The generic expanders will use our new subdi3 expander if this pattern is missing and that can handle the negate case just fine. * config/arm/arm-modes.def (CC_RSB): New CC mode. * config/arm/predicates.md (arm_borrow_operation): Handle CC_RSBmode. * config/arm/arm.c (arm_select_cc_mode): Detect when we should return CC_RSBmode. (maybe_get_arm_condition_code): Handle CC_RSBmode. * config/arm/arm.md (subsi3_carryin): Make this pattern available to expand. (subdi3): Rewrite to early-expand the sub-operations. (rsb_im_compare): New pattern. (negdi2): Delete. (negdi2_insn): Delete. (arm_negsi2): Correct type attribute to alu_imm. (negsi2_0compare): New insn pattern. (negsi2_carryin): New insn pattern. --- gcc/config/arm/arm-modes.def | 4 + gcc/config/arm/arm.c | 23 ++++++ gcc/config/arm/arm.md | 141 ++++++++++++++++++++++++++++------- gcc/config/arm/predicates.md | 2 +- 4 files changed, 141 insertions(+), 29 deletions(-) diff --git a/gcc/config/arm/arm-modes.def b/gcc/config/arm/arm-modes.def index 8f131c369b5..4fa7f1b43e5 100644 --- a/gcc/config/arm/arm-modes.def +++ b/gcc/config/arm/arm-modes.def @@ -36,6 +36,9 @@ ADJUST_FLOAT_FORMAT (HF, ((arm_fp16_format == ARM_FP16_FORMAT_ALTERNATIVE) CC_Nmode should be used if only the N (sign) flag is set correctly 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 (used for DImode signed comparisons). CCmode should be used otherwise. */ @@ -45,6 +48,7 @@ CC_MODE (CC_Z); CC_MODE (CC_CZ); CC_MODE (CC_NCV); CC_MODE (CC_SWP); +CC_MODE (CC_RSB); CC_MODE (CCFP); CC_MODE (CCFPE); CC_MODE (CC_DNE); diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c index db18651346f..9a779e24cac 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -15214,6 +15214,17 @@ 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 + 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)) + return CC_RSBmode; + if (GET_MODE (x) == QImode && (op == EQ || op == NE)) return CC_Zmode; @@ -23629,6 +23640,18 @@ 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: switch (comp_code) { diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md index fbe154a9873..99d931525f8 100644 --- a/gcc/config/arm/arm.md +++ b/gcc/config/arm/arm.md @@ -989,7 +989,7 @@ (define_insn "subsi3_compare1" (set_attr "type" "alus_sreg")] ) -(define_insn "*subsi3_carryin" +(define_insn "subsi3_carryin" [(set (match_operand:SI 0 "s_register_operand" "=r,r,r") (minus:SI (minus:SI (match_operand:SI 1 "reg_or_int_operand" "r,I,Pz") (match_operand:SI 2 "s_register_operand" "r,r,r")) @@ -1094,12 +1094,72 @@ (define_expand "adddf3" (define_expand "subdi3" [(parallel [(set (match_operand:DI 0 "s_register_operand") - (minus:DI (match_operand:DI 1 "s_register_operand") + (minus:DI (match_operand:DI 1 "reg_or_int_operand") (match_operand:DI 2 "s_register_operand"))) (clobber (reg:CC CC_REGNUM))])] "TARGET_EITHER" " -") + if (TARGET_THUMB1) + { + if (!REG_P (operands[1])) + operands[1] = force_reg (DImode, operands[1]); + } + else + { + rtx lo_result, hi_result, lo_dest, hi_dest; + rtx lo_op1, hi_op1, lo_op2, hi_op2; + rtx condition; + + /* Since operands[1] may be an integer, pass it second, so that + any necessary simplifications will be done on the decomposed + constant. */ + arm_decompose_di_binop (operands[2], operands[1], &lo_op2, &hi_op2, + &lo_op1, &hi_op1); + lo_result = lo_dest = gen_lowpart (SImode, operands[0]); + hi_result = hi_dest = gen_highpart (SImode, operands[0]); + + if (!arm_rhs_operand (lo_op1, SImode)) + lo_op1 = force_reg (SImode, lo_op1); + + if ((TARGET_THUMB2 && ! s_register_operand (hi_op1, SImode)) + || !arm_rhs_operand (hi_op1, SImode)) + hi_op1 = force_reg (SImode, hi_op1); + + rtx cc_reg; + if (lo_op1 == const0_rtx) + { + cc_reg = gen_rtx_REG (CC_RSBmode, CC_REGNUM); + emit_insn (gen_negsi2_0compare (lo_dest, lo_op2)); + } + else if (CONST_INT_P (lo_op1)) + { + cc_reg = gen_rtx_REG (CC_RSBmode, CC_REGNUM); + emit_insn (gen_rsb_imm_compare (lo_dest, lo_op1, lo_op2, + GEN_INT (~UINTVAL (lo_op1)))); + } + else + { + cc_reg = gen_rtx_REG (CCmode, CC_REGNUM); + emit_insn (gen_subsi3_compare (lo_dest, lo_op1, lo_op2)); + } + + condition = gen_rtx_LTU (SImode, cc_reg, const0_rtx); + + if (hi_op1 == const0_rtx) + emit_insn (gen_negsi2_carryin (hi_dest, hi_op2, condition)); + else + emit_insn (gen_subsi3_carryin (hi_dest, hi_op1, hi_op2, condition)); + + if (lo_result != lo_dest) + emit_move_insn (lo_result, lo_dest); + + if (hi_result != hi_dest) + emit_move_insn (hi_result, hi_dest); + + DONE; + } + " +) (define_insn "*arm_subdi3" [(set (match_operand:DI 0 "arm_general_register_operand" "=&r,&r,&r") @@ -1213,7 +1273,23 @@ (define_insn "subsi3_compare" subs%?\\t%0, %1, %2 rsbs%?\\t%0, %2, %1" [(set_attr "conds" "set") - (set_attr "type" "alus_imm,alus_sreg,alus_sreg")] + (set_attr "type" "alus_imm,alus_sreg,alus_imm")] +) + +;; To keep the comparison in canonical form we express it as (~reg cmp ~0) +;; rather than (0 cmp reg). This gives the same results for unsigned +;; and equality compares which is what we mostly need here. +(define_insn "rsb_imm_compare" + [(set (reg:CC_RSB CC_REGNUM) + (compare:CC_RSB (not:SI (match_operand:SI 2 "s_register_operand" "r")) + (match_operand 3 "const_int_operand" ""))) + (set (match_operand:SI 0 "s_register_operand" "=r") + (minus:SI (match_operand 1 "arm_immediate_operand" "I") + (match_dup 2)))] + "TARGET_32BIT && ~UINTVAL (operands[1]) == UINTVAL (operands[3])" + "rsbs\\t%0, %2, %1" + [(set_attr "conds" "set") + (set_attr "type" "alus_imm")] ) (define_expand "subsf3" @@ -3726,29 +3802,6 @@ (define_insn "negdi2_compare" (set_attr "type" "multiple")] ) -(define_expand "negdi2" - [(parallel - [(set (match_operand:DI 0 "s_register_operand") - (neg:DI (match_operand:DI 1 "s_register_operand"))) - (clobber (reg:CC CC_REGNUM))])] - "TARGET_EITHER" -) - -;; The constraints here are to prevent a *partial* overlap (where %Q0 == %R1). -(define_insn "*negdi2_insn" - [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") - (neg:DI (match_operand:DI 1 "s_register_operand" "r,r"))) - (clobber (reg:CC CC_REGNUM))] - "TARGET_32BIT" - "@ - rsbs\\t%Q0, %Q1, #0; rsc\\t%R0, %R1, #0 - negs\\t%Q0, %Q1; sbc\\t%R0, %R1, %R1, lsl #1" - [(set_attr "conds" "clob") - (set_attr "arch" "a,t2") - (set_attr "length" "8") - (set_attr "type" "multiple")] -) - (define_expand "negsi2" [(set (match_operand:SI 0 "s_register_operand") (neg:SI (match_operand:SI 1 "s_register_operand")))] @@ -3765,7 +3818,39 @@ (define_insn "*arm_negsi2" (set_attr "predicable_short_it" "yes,no") (set_attr "arch" "t2,*") (set_attr "length" "4") - (set_attr "type" "alu_sreg")] + (set_attr "type" "alu_imm")] +) + +;; To keep the comparison in canonical form we express it as (~reg cmp ~0) +;; rather than (0 cmp reg). This gives the same results for unsigned +;; and equality compares which is what we mostly need here. +(define_insn "negsi2_0compare" + [(set (reg:CC_RSB CC_REGNUM) + (compare:CC_RSB (not:SI (match_operand:SI 1 "s_register_operand" "l,r")) + (const_int -1))) + (set (match_operand:SI 0 "s_register_operand" "=l,r") + (neg:SI (match_dup 1)))] + "TARGET_32BIT" + "@ + negs\\t%0, %1 + rsbs\\t%0, %1, #0" + [(set_attr "conds" "set") + (set_attr "arch" "t2,*") + (set_attr "length" "2,*") + (set_attr "type" "alus_imm")] +) + +(define_insn "negsi2_carryin" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (minus:SI (neg:SI (match_operand:SI 1 "s_register_operand" "r,r")) + (match_operand:SI 2 "arm_borrow_operation" "")))] + "TARGET_32BIT" + "@ + rsc\\t%0, %1, #0 + sbc\\t%0, %1, %1, lsl #1" + [(set_attr "conds" "use") + (set_attr "arch" "a,t2") + (set_attr "type" "adc_imm,adc_reg")] ) (define_expand "negsf2" diff --git a/gcc/config/arm/predicates.md b/gcc/config/arm/predicates.md index 8b36e7ee462..e6766a97fc4 100644 --- a/gcc/config/arm/predicates.md +++ b/gcc/config/arm/predicates.md @@ -371,7 +371,7 @@ (define_special_predicate "arm_borrow_operation" machine_mode ccmode = GET_MODE (op0); if (ccmode == CC_Cmode) return GET_CODE (op) == GEU; - else if (ccmode == CCmode) + else if (ccmode == CCmode || ccmode == CC_RSBmode) return GET_CODE (op) == LTU; return false; }