From patchwork Mon Jan 10 20:31:53 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Henderson X-Patchwork-Id: 78224 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]) by ozlabs.org (Postfix) with SMTP id 2F8F9B7104 for ; Tue, 11 Jan 2011 07:36:04 +1100 (EST) Received: (qmail 22146 invoked by alias); 10 Jan 2011 20:33:43 -0000 Received: (qmail 21226 invoked by uid 22791); 10 Jan 2011 20:33:23 -0000 X-SWARE-Spam-Status: No, hits=-1.8 required=5.0 tests=AWL,BAYES_00 X-Spam-Check-By: sourceware.org Received: from eggs.gnu.org (HELO eggs.gnu.org) (140.186.70.92) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Mon, 10 Jan 2011 20:33:02 +0000 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1PcOQE-0007Cn-Ub for gcc-patches@gcc.gnu.org; Mon, 10 Jan 2011 15:33:00 -0500 Received: from a.mail.sonic.net ([64.142.16.245]:54832) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1PcOQE-0007CR-GA for gcc-patches@gcc.gnu.org; Mon, 10 Jan 2011 15:32:58 -0500 Received: from are.twiddle.net (are.twiddle.net [75.101.38.216]) by a.mail.sonic.net (8.13.8.Beta0-Sonic/8.13.7) with ESMTP id p0AKWvI1015950 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Mon, 10 Jan 2011 12:32:57 -0800 Received: from anchor.twiddle.home (anchor.twiddle.home [172.31.0.4]) by are.twiddle.net (8.14.4/8.14.4) with ESMTP id p0AKWviD006811; Mon, 10 Jan 2011 12:32:57 -0800 Received: from anchor.twiddle.home (localhost.localdomain [127.0.0.1]) by anchor.twiddle.home (8.14.4/8.14.4) with ESMTP id p0AKWsUC019745; Mon, 10 Jan 2011 12:32:55 -0800 Received: (from rth@localhost) by anchor.twiddle.home (8.14.4/8.14.4/Submit) id p0AKWrCa019744; Mon, 10 Jan 2011 12:32:53 -0800 From: Richard Henderson To: gcc-patches@gcc.gnu.org Cc: nickc@redhat.com, law@redhat.com, Richard Henderson Subject: [PATCH 24/28] mn10300: Implement adddi3, subdi3. Date: Mon, 10 Jan 2011 12:31:53 -0800 Message-Id: <1294691517-19580-25-git-send-email-rth@redhat.com> In-Reply-To: <1294691517-19580-1-git-send-email-rth@redhat.com> References: <1294691517-19580-1-git-send-email-rth@redhat.com> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.4-2.6 X-IsSubscribed: yes 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 From: Richard Henderson Via expander, pre- and post-reload patterns. The pre-reload pattern is defined to allow lower_subregs totally split the DImode values. --- gcc/config/mn10300/mn10300.md | 321 ++++++++++++++++++++++++++++++++++++++ gcc/config/mn10300/predicates.md | 5 + 2 files changed, 326 insertions(+), 0 deletions(-) diff --git a/gcc/config/mn10300/mn10300.md b/gcc/config/mn10300/mn10300.md index fae87e9..edfdb5d 100644 --- a/gcc/config/mn10300/mn10300.md +++ b/gcc/config/mn10300/mn10300.md @@ -534,6 +534,172 @@ [(set_attr "timings" "11,22")] ) +;; A helper to expand the above, with the CC_MODE filled in. +(define_expand "addsi3_flags" + [(parallel [(set (match_operand:SI 0 "register_operand") + (plus:SI (match_operand:SI 1 "register_operand") + (match_operand:SI 2 "nonmemory_operand"))) + (set (reg:CCZNC CC_REG) + (compare:CCZNC (plus:SI (match_dup 1) (match_dup 2)) + (const_int 0)))])] + "" +) + +(define_insn "addc_internal" + [(set (match_operand:SI 0 "register_operand" "=D,r,r") + (plus:SI + (plus:SI + (ltu:SI (reg:CC CC_REG) (const_int 0)) + (match_operand:SI 1 "register_operand" "%0,0,r")) + (match_operand:SI 2 "reg_or_am33_const_operand" " D,i,r"))) + (clobber (reg:CC CC_REG))] + "reload_completed" + "@ + addc %2,%0 + addc %2,%0 + addc %2,%1,%0" + [(set_attr "isa" "*,am33,am33")] +) + +(define_expand "adddi3" + [(set (match_operand:DI 0 "register_operand" "") + (plus:DI (match_operand:DI 1 "register_operand" "") + (match_operand:DI 2 "nonmemory_operand" "")))] + "" +{ + rtx op0l, op0h, op1l, op1h, op2l, op2h; + + op0l = gen_lowpart (SImode, operands[0]); + op1l = gen_lowpart (SImode, operands[1]); + op2l = gen_lowpart (SImode, operands[2]); + op0h = gen_highpart (SImode, operands[0]); + op1h = gen_highpart (SImode, operands[1]); + op2h = gen_highpart_mode (SImode, DImode, operands[2]); + + if (!reg_or_am33_const_operand (op2h, SImode)) + op2h = force_reg (SImode, op2h); + + emit_insn (gen_adddi3_internal (op0l, op0h, op1l, op2l, op1h, op2h)); + DONE; +}) + +;; Note that reload only supports one commutative operand. Thus we cannot +;; auto-swap both the high and low outputs with their matching constraints. +;; For MN103, we're strapped for registers but thankfully the alternatives +;; are few. For AM33, it becomes much easier to not represent the early +;; clobber and 6 permutations of immediate and three-operand adds, but +;; instead allocate a scratch register and do the expansion by hand. + +(define_insn_and_split "adddi3_internal" + [(set (match_operand:SI 0 "register_operand" "=r, r, r") + (plus:SI (match_operand:SI 2 "register_operand" "%0, 0, r") + (match_operand:SI 3 "nonmemory_operand" "ri,ri,ri"))) + (set (match_operand:SI 1 "register_operand" "=D, D, r") + (plus:SI + (plus:SI + (ltu:SI (plus:SI (match_dup 2) (match_dup 3)) (match_dup 2)) + (match_operand:SI 4 "register_operand" " 1, D, r")) + (match_operand:SI 5 "reg_or_am33_const_operand" " D, 1,ri"))) + (clobber (match_scratch:SI 6 "=X, X,&r")) + (clobber (reg:CC CC_REG))] + "" + "#" + "reload_completed" + [(const_int 0)] +{ + rtx op0l = operands[0]; + rtx op0h = operands[1]; + rtx op1l = operands[2]; + rtx op2l = operands[3]; + rtx op1h = operands[4]; + rtx op2h = operands[5]; + rtx scratch = operands[6]; + rtx x; + + if (reg_overlap_mentioned_p (op0l, op1h)) + { + emit_move_insn (scratch, op0l); + op1h = scratch; + if (reg_overlap_mentioned_p (op0l, op2h)) + op2h = scratch; + } + else if (reg_overlap_mentioned_p (op0l, op2h)) + { + emit_move_insn (scratch, op0l); + op2h = scratch; + } + + if (rtx_equal_p (op0l, op1l)) + ; + else if (rtx_equal_p (op0l, op2l)) + x = op1l, op1l = op2l, op2l = x; + else + { + gcc_assert (TARGET_AM33); + if (!REG_P (op2l)) + { + emit_move_insn (op0l, op2l); + op2l = op1l; + op1l = op0l; + } + } + emit_insn (gen_addsi3_flags (op0l, op1l, op2l)); + + if (rtx_equal_p (op0h, op1h)) + ; + else if (rtx_equal_p (op0h, op2h)) + x = op1h, op1h = op2h, op2h = x; + else + { + gcc_assert (TARGET_AM33); + if (!REG_P (op2h)) + { + emit_move_insn (op0h, op2h); + op2h = op1h; + op1h = op0h; + } + } + emit_insn (gen_addc_internal (op0h, op1h, op2h)); + DONE; +} + [(set_attr "isa" "*,*,am33")] +) + +;; The following pattern is generated by combine when it proves that one +;; of the inputs to the low-part of the double-word add is zero, and thus +;; no carry is generated into the high-part. + +(define_insn_and_split "*adddi3_degenerate" + [(set (match_operand:SI 0 "register_operand" "=&r,&r") + (match_operand:SI 2 "nonmemory_operand" " 0, 0")) + (set (match_operand:SI 1 "register_operand" "=r , r") + (plus:SI (match_operand:SI 3 "register_operand" "%1 , r") + (match_operand:SI 4 "nonmemory_operand" "ri, r"))) + (clobber (reg:CC CC_REG))] + "" + "#" + "" + [(const_int 0)] +{ + rtx scratch = NULL_RTX; + if (!rtx_equal_p (operands[0], operands[2])) + { + gcc_assert (!reg_overlap_mentioned_p (operands[0], operands[1])); + if (reg_overlap_mentioned_p (operands[0], operands[3]) + || reg_overlap_mentioned_p (operands[0], operands[4])) + { + scratch = gen_reg_rtx (SImode); + emit_move_insn (scratch, operands[2]); + } + else + emit_move_insn (operands[0], operands[2]); + } + emit_insn (gen_addsi3 (operands[1], operands[3], operands[4])); + if (scratch) + emit_move_insn (operands[0], scratch); + DONE; +}) + ;; ---------------------------------------------------------------------- ;; SUBTRACT INSTRUCTIONS ;; ---------------------------------------------------------------------- @@ -566,6 +732,161 @@ (set_attr "timings" "11,22")] ) +;; A helper to expand the above, with the CC_MODE filled in. +(define_expand "subsi3_flags" + [(parallel [(set (match_operand:SI 0 "register_operand") + (minus:SI (match_operand:SI 1 "register_operand") + (match_operand:SI 2 "nonmemory_operand"))) + (set (reg:CCZNC CC_REG) + (compare:CCZNC (minus:SI (match_dup 1) (match_dup 2)) + (const_int 0)))])] + "" +) + +(define_insn "subc_internal" + [(set (match_operand:SI 0 "register_operand" "=D,r,r") + (minus:SI + (minus:SI (match_operand:SI 1 "register_operand" " 0,0,r") + (match_operand:SI 2 "reg_or_am33_const_operand" " D,i,r")) + (geu:SI (reg:CC CC_REG) (const_int 0)))) + (clobber (reg:CC CC_REG))] + "reload_completed" + "@ + subc %2,%0 + subc %2,%0 + subc %2,%1,%0" + [(set_attr "isa" "*,am33,am33")] +) + +(define_expand "subdi3" + [(set (match_operand:DI 0 "register_operand" "") + (minus:DI (match_operand:DI 1 "register_operand" "") + (match_operand:DI 2 "nonmemory_operand" "")))] + "" +{ + rtx op0l, op0h, op1l, op1h, op2l, op2h; + + op0l = gen_lowpart (SImode, operands[0]); + op1l = gen_lowpart (SImode, operands[1]); + op2l = gen_lowpart (SImode, operands[2]); + op0h = gen_highpart (SImode, operands[0]); + op1h = gen_highpart (SImode, operands[1]); + op2h = gen_highpart_mode (SImode, DImode, operands[2]); + + if (!reg_or_am33_const_operand (op2h, SImode)) + op2h = force_reg (SImode, op2h); + + emit_insn (gen_subdi3_internal (op0l, op0h, op1l, op1h, op2l, op2h)); + DONE; +}) + +;; As with adddi3, the use of the scratch register helps reduce the +;; number of permutations for AM33. +;; ??? The early clobber on op0 avoids a reload bug wherein both output +;; registers are set the same. Consider negate, where both op2 and op3 +;; are 0, are csed to the same input register, and reload fails to undo +;; the cse when satisfying the matching constraints. + +(define_insn_and_split "subdi3_internal" + [(set (match_operand:SI 0 "register_operand" "=&r, r") + (minus:SI + (match_operand:SI 2 "register_operand" " 0, r") + (match_operand:SI 4 "nonmemory_operand" " ri,ri"))) + (set (match_operand:SI 1 "register_operand" "=D , r") + (minus:SI + (minus:SI + (match_operand:SI 3 "register_operand" " 1, r") + (match_operand:SI 5 "reg_or_am33_const_operand" " D,ri")) + (ltu:SI (match_dup 2) (match_dup 4)))) + (clobber (match_scratch:SI 6 "=X ,&r")) + (clobber (reg:CC CC_REG))] + "" + "#" + "reload_completed" + [(const_int 0)] +{ + rtx op0l = operands[0]; + rtx op0h = operands[1]; + rtx op1l = operands[2]; + rtx op1h = operands[3]; + rtx op2l = operands[4]; + rtx op2h = operands[5]; + rtx scratch = operands[6]; + + if (reg_overlap_mentioned_p (op0l, op1h)) + { + emit_move_insn (scratch, op0l); + op1h = scratch; + if (reg_overlap_mentioned_p (op0l, op2h)) + op2h = scratch; + } + else if (reg_overlap_mentioned_p (op0l, op2h)) + { + emit_move_insn (scratch, op0l); + op2h = scratch; + } + + if (!rtx_equal_p (op0l, op1l)) + { + gcc_assert (TARGET_AM33); + if (!REG_P (op2l)) + { + emit_move_insn (op0l, op1l); + op1l = op0l; + } + } + emit_insn (gen_subsi3_flags (op0l, op1l, op2l)); + + if (!rtx_equal_p (op0h, op1h)) + { + gcc_assert (TARGET_AM33); + if (!REG_P (op2h)) + { + emit_move_insn (op0h, op1h); + op1h = op0h; + } + } + emit_insn (gen_subc_internal (op0h, op1h, op2h)); + DONE; +} + [(set_attr "isa" "*,am33")] +) + +;; The following pattern is generated by combine when it proves that one +;; of the inputs to the low-part of the double-word sub is zero, and thus +;; no carry is generated into the high-part. + +(define_insn_and_split "*subdi3_degenerate" + [(set (match_operand:SI 0 "register_operand" "=&r,&r") + (match_operand:SI 2 "nonmemory_operand" " 0, 0")) + (set (match_operand:SI 1 "register_operand" "=r , r") + (minus:SI (match_operand:SI 3 "register_operand" " 1, r") + (match_operand:SI 4 "nonmemory_operand" " ri, r"))) + (clobber (reg:CC CC_REG))] + "" + "#" + "" + [(const_int 0)] +{ + rtx scratch = NULL_RTX; + if (!rtx_equal_p (operands[0], operands[2])) + { + gcc_assert (!reg_overlap_mentioned_p (operands[0], operands[1])); + if (reg_overlap_mentioned_p (operands[0], operands[3]) + || reg_overlap_mentioned_p (operands[0], operands[4])) + { + scratch = gen_reg_rtx (SImode); + emit_move_insn (scratch, operands[2]); + } + else + emit_move_insn (operands[0], operands[2]); + } + emit_insn (gen_subsi3 (operands[1], operands[3], operands[4])); + if (scratch) + emit_move_insn (operands[0], scratch); + DONE; +}) + (define_insn_and_split "negsi2" [(set (match_operand:SI 0 "register_operand" "=D,&r") (neg:SI (match_operand:SI 1 "register_operand" " 0, r"))) diff --git a/gcc/config/mn10300/predicates.md b/gcc/config/mn10300/predicates.md index 4badebb..8316990 100644 --- a/gcc/config/mn10300/predicates.md +++ b/gcc/config/mn10300/predicates.md @@ -43,6 +43,11 @@ || XEXP (op, 1) == stack_pointer_rtx; }) +(define_predicate "reg_or_am33_const_operand" + (ior (match_operand 0 "register_operand") + (and (match_test "TARGET_AM33") + (match_operand 0 "immediate_operand")))) + (define_predicate "label_ref_operand" (match_code "label_ref"))