From patchwork Mon Nov 21 19:31:26 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Georg-Johann Lay X-Patchwork-Id: 126909 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 20C86B6F7D for ; Tue, 22 Nov 2011 06:33:07 +1100 (EST) Received: (qmail 13056 invoked by alias); 21 Nov 2011 19:33:05 -0000 Received: (qmail 13002 invoked by uid 22791); 21 Nov 2011 19:33:02 -0000 X-SWARE-Spam-Status: No, hits=1.1 required=5.0 tests=AWL, BAYES_50, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, RCVD_IN_DNSWL_NONE, SARE_HTML_INV_TAG, TW_HR, TW_RQ, TW_TQ X-Spam-Check-By: sourceware.org Received: from mo-p00-ob.rzone.de (HELO mo-p00-ob.rzone.de) (81.169.146.162) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Mon, 21 Nov 2011 19:32:09 +0000 X-RZG-AUTH: :LXoWVUeid/7A29J/hMvvT2k715jHQaJercGObUOFkj18odoYNahU4Q== X-RZG-CLASS-ID: mo00 Received: from [192.168.0.22] (business-188-111-022-002.static.arcor-ip.net [188.111.22.2]) by smtp.strato.de (klopstock mo16) (RZmta 26.10 AUTH) with ESMTPA id L03f11nALIcIEk ; Mon, 21 Nov 2011 20:31:26 +0100 (MET) Message-ID: <4ECAA70E.5050205@gjlay.de> Date: Mon, 21 Nov 2011 20:31:26 +0100 From: Georg-Johann Lay User-Agent: Thunderbird 2.0.0.24 (X11/20100302) MIME-Version: 1.0 To: gcc-patches@gcc.gnu.org CC: Denis Chertykov , Eric Weddington , Anatoly Sokolov , Richard Henderson Subject: [Patch,AVR] Light-weight DImode implementation. 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 This adds support for DImode insns that don't operate byte-wise like NEG, COMPARE, PLUS, MINUS, ASHIFT, LSHIFTRT, ASHIFTRT, ROTATE. The crucial point is that there is no movdi, with the following reasoning as cited from new avr-dimode.md: ;; The purpose of this file is to provide a light-weight DImode ;; implementation for AVR. The trouble with DImode is that tree -> RTL ;; lowering leads to really unpleasant code for operations that don't ;; work byte-wise like NEG, PLUS, MINUS, etc. Defining optabs entries for ;; them won't help because the optab machinery assumes these operations ;; are cheap and does not check if a libgcc implementation is available. ;; ;; The DImode insns are all straight forward -- except movdi. The approach ;; of this implementation is to provide DImode insns without the burden of ;; introducing movdi. ;; ;; The caveat is that if there are insns for some mode, there must also be a ;; respective move insn that describes reloads. Therefore, this ;; implementation uses an accumulator-based model with two hard-coded, ;; accumulator-like registers ;; ;; A[] = reg:DI 18 ;; B[] = reg:DI 10 ;; ;; so that no DImode insn contains pseudos or needs reloading. Comments are welcome whether this is reasonable or bullshit ;-) The implementation is just some 300 lines and works smooth with the test suite and libgcc and avr-libc generated with -m64, of course. All insns/expanders in the new avr-dimode.md are triggered by -m64 which is off per default. The new option is because I excepted problems with the patch, but it runs smooth since the first line so that the option can be dropped if the explanation above holds. The changes to the rest of the backend are just hand-full of lines :-) As said above, test suite passes fine both woth -m64 off and with -m64 turn on and with libgcc/libc built with that switch. Ok? Johann gcc/ * config/avr/avr.opt (-m64): New option. * config/avr/avr-dimode.md: New file. * config/avr/avr.md: Include it. (adjust_len): Add plus64, compare64. (HIDI): Remove code iterator. (code_stdname): New code attribute. (rotx, rotsmode): Remove DI. (rotl3, *rotw, *rotb): Use HISI instead of HIDI as code iterator. * config/avr/avr-protos.h (avr_out_plus64, avr_out_compare64): New. * config/avr/avr.c (avr_out_compare): Handle DImode. (avr_out_compare64, avr_out_plus64): New functions. (avr_out_plus_1): Use simplify_unary_operation to negate xval. (adjust_insn_length): Handle ADJUST_LEN_COMPARE64, ADJUST_LEN_PLUS64. (avr_compare_pattern): Skip DImode comparisons. libgcc/ * config/avr/t-avr (LIB1ASMFUNCS): Add _adddi3, _adddi3_s8, _subdi3, _cmpdi2, _cmpdi2_s8, _rotldi3. * config/avr/lib1funcs.S (__adddi3, __adddi3_s8, __subdi3, __cmpdi2, __cmpdi2_s8, __rotldi3): New functions. Index: gcc/config/avr/avr-dimode.md =================================================================== --- gcc/config/avr/avr-dimode.md (revision 0) +++ gcc/config/avr/avr-dimode.md (revision 0) @@ -0,0 +1,283 @@ +;; Machine description for GNU compiler, +;; for Atmel AVR micro controllers. +;; Copyright (C) 1998 - 2011 +;; Free Software Foundation, Inc. +;; Contributed by Georg Lay (avr@gjlay.de) +;; +;; This file is part of GCC. +;; +;; GCC is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 3, or (at your option) +;; any later version. +;; +;; GCC is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with GCC; see the file COPYING3. If not see +;; . + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; The purpose of this file is to provide a light-weight DImode +;; implementation for AVR. The trouble with DImode is that tree -> RTL +;; lowering leads to really unpleasant code for operations that don't +;; work byte-wise like NEG, PLUS, MINUS, etc. Defining optabs entries for +;; them won't help because the optab machinery assumes these operations +;; are cheap and does not check if a libgcc implementation is available. +;; +;; The DImode insns are all straight forward -- except movdi. The approach +;; of this implementation is to provide DImode insns without the burden of +;; introducing movdi. +;; +;; The caveat is that if there are insns for some mode, there must also be a +;; respective move insn that describes reloads. Therefore, this +;; implementation uses an accumulator-based model with two hard-coded, +;; accumulator-like registers +;; +;; A[] = reg:DI 18 +;; B[] = reg:DI 10 +;; +;; so that no DImode insn contains pseudos or needs reloading. + +(define_constants + [(ACC_A 18) + (ACC_B 10)]) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Addition +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(define_expand "adddi3" + [(parallel [(match_operand:DI 0 "general_operand" "") + (match_operand:DI 1 "general_operand" "") + (match_operand:DI 2 "general_operand" "")])] + "avr_have_dimode" + { + rtx acc_a = gen_rtx_REG (DImode, ACC_A); + + emit_move_insn (acc_a, operands[1]); + + if (s8_operand (operands[2], VOIDmode)) + { + emit_move_insn (gen_rtx_REG (QImode, REG_X), operands[2]); + emit_insn (gen_adddi3_const8_insn ()); + } + else if (CONST_INT_P (operands[2]) + || CONST_DOUBLE_P (operands[2])) + { + emit_insn (gen_adddi3_const_insn (operands[2])); + } + else + { + emit_move_insn (gen_rtx_REG (DImode, ACC_B), operands[2]); + emit_insn (gen_adddi3_insn ()); + } + + emit_move_insn (operands[0], acc_a); + DONE; + }) + +(define_insn "adddi3_insn" + [(set (reg:DI ACC_A) + (plus:DI (reg:DI ACC_A) + (reg:DI ACC_B)))] + "avr_have_dimode" + "%~call __adddi3" + [(set_attr "adjust_len" "call") + (set_attr "cc" "clobber")]) + +(define_insn "adddi3_const8_insn" + [(set (reg:DI ACC_A) + (plus:DI (reg:DI ACC_A) + (sign_extend:DI (reg:QI REG_X))))] + "avr_have_dimode" + "%~call __adddi3_s8" + [(set_attr "adjust_len" "call") + (set_attr "cc" "clobber")]) + +(define_insn "adddi3_const_insn" + [(set (reg:DI ACC_A) + (plus:DI (reg:DI ACC_A) + (match_operand:DI 0 "const_double_operand" "n")))] + "avr_have_dimode + && !s8_operand (operands[0], VOIDmode)" + { + return avr_out_plus64 (operands[0], NULL); + } + [(set_attr "adjust_len" "plus64") + (set_attr "cc" "clobber")]) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Subtraction +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(define_expand "subdi3" + [(parallel [(match_operand:DI 0 "general_operand" "") + (match_operand:DI 1 "general_operand" "") + (match_operand:DI 2 "general_operand" "")])] + "avr_have_dimode" + { + rtx acc_a = gen_rtx_REG (DImode, ACC_A); + + emit_move_insn (acc_a, operands[1]); + emit_move_insn (gen_rtx_REG (DImode, ACC_B), operands[2]); + emit_insn (gen_subdi3_insn ()); + emit_move_insn (operands[0], acc_a); + DONE; + }) + +(define_insn "subdi3_insn" + [(set (reg:DI ACC_A) + (minus:DI (reg:DI ACC_A) + (reg:DI ACC_B)))] + "avr_have_dimode" + "%~call __subdi3" + [(set_attr "adjust_len" "call") + (set_attr "cc" "set_czn")]) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Negation +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(define_expand "negdi2" + [(parallel [(match_operand:DI 0 "general_operand" "") + (match_operand:DI 1 "general_operand" "")])] + "avr_have_dimode" + { + rtx acc_a = gen_rtx_REG (DImode, ACC_A); + + emit_move_insn (acc_a, operands[1]); + emit_insn (gen_negdi2_insn ()); + emit_move_insn (operands[0], acc_a); + DONE; + }) + +(define_insn "negdi2_insn" + [(set (reg:DI ACC_A) + (neg:DI (reg:DI ACC_A)))] + "avr_have_dimode" + "%~call __negdi2" + [(set_attr "adjust_len" "call") + (set_attr "cc" "clobber")]) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Comparison +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(define_expand "conditional_jump" + [(set (pc) + (if_then_else + (match_operator 0 "ordered_comparison_operator" [(cc0) + (const_int 0)]) + (label_ref (match_operand 1 "" "")) + (pc)))] + "avr_have_dimode") + +(define_expand "cbranchdi4" + [(parallel [(match_operand:DI 1 "register_operand" "") + (match_operand:DI 2 "nonmemory_operand" "") + (match_operator 0 "ordered_comparison_operator" [(cc0) + (const_int 0)]) + (label_ref (match_operand 3 "" ""))])] + "avr_have_dimode" + { + rtx acc_a = gen_rtx_REG (DImode, ACC_A); + + emit_move_insn (acc_a, operands[1]); + + if (s8_operand (operands[2], VOIDmode)) + { + emit_move_insn (gen_rtx_REG (QImode, REG_X), operands[2]); + emit_insn (gen_compare_const8_di2 ()); + } + else if (CONST_INT_P (operands[2]) + || CONST_DOUBLE_P (operands[2])) + { + emit_insn (gen_compare_const_di2 (operands[2])); + } + else + { + emit_move_insn (gen_rtx_REG (DImode, ACC_B), operands[2]); + emit_insn (gen_compare_di2 ()); + } + + emit_jump_insn (gen_conditional_jump (operands[0], operands[3])); + DONE; + }) + +(define_insn "compare_di2" + [(set (cc0) + (compare (reg:DI ACC_A) + (reg:DI ACC_B)))] + "avr_have_dimode" + "%~call __cmpdi2" + [(set_attr "adjust_len" "call") + (set_attr "cc" "compare")]) + +(define_insn "compare_const8_di2" + [(set (cc0) + (compare (reg:DI ACC_A) + (sign_extend:DI (reg:QI REG_X))))] + "avr_have_dimode" + "%~call __cmpdi2_s8" + [(set_attr "adjust_len" "call") + (set_attr "cc" "compare")]) + +(define_insn "compare_const_di2" + [(set (cc0) + (compare (reg:DI ACC_A) + (match_operand:DI 0 "const_double_operand" "n"))) + (clobber (match_scratch:QI 1 "=&d"))] + "avr_have_dimode + && !s8_operand (operands[0], VOIDmode)" + { + return avr_out_compare64 (insn, operands, NULL); + } + [(set_attr "adjust_len" "compare64") + (set_attr "cc" "compare")]) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Shifts and Rotate +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(define_code_iterator di_shifts + [ashift ashiftrt lshiftrt rotate]) + +;; Shift functions from libgcc are called without defining these insns, +;; but with them we can describe their reduced register footprint. + +;; "ashldi3" +;; "ashrdi3" +;; "lshrdi3" +;; "rotldi3" +(define_expand "di3" + [(parallel [(match_operand:DI 0 "general_operand" "") + (di_shifts:DI (match_operand:DI 1 "general_operand" "") + (match_operand:QI 2 "general_operand" ""))])] + "avr_have_dimode" + { + rtx acc_a = gen_rtx_REG (DImode, ACC_A); + + emit_move_insn (acc_a, operands[1]); + emit_move_insn (gen_rtx_REG (QImode, 16), operands[2]); + emit_insn (gen_di3_insn ()); + emit_move_insn (operands[0], acc_a); + DONE; + }) + +(define_insn "di3_insn" + [(set (reg:DI ACC_A) + (di_shifts:DI (reg:DI ACC_A) + (reg:QI 16)))] + "avr_have_dimode" + "%~call __di3" + [(set_attr "adjust_len" "call") + (set_attr "cc" "clobber")]) Index: gcc/config/avr/avr.md =================================================================== --- gcc/config/avr/avr.md (revision 181592) +++ gcc/config/avr/avr.md (working copy) @@ -131,8 +131,8 @@ (define_attr "length" "" ;; Otherwise do special processing depending on the attribute. (define_attr "adjust_len" - "out_bitop, out_plus, out_plus_noclobber, addto_sp, - tsthi, tstpsi, tstsi, compare, call, + "out_bitop, out_plus, out_plus_noclobber, plus64, addto_sp, + tsthi, tstpsi, tstsi, compare, compare64, call, mov8, mov16, mov24, mov32, reload_in16, reload_in24, reload_in32, xload, movmem, ashlqi, ashrqi, lshrqi, @@ -206,7 +206,6 @@ (define_mode_iterator QIHI [(QI "") (HI (define_mode_iterator QIHI2 [(QI "") (HI "")]) (define_mode_iterator QISI [(QI "") (HI "") (PSI "") (SI "")]) (define_mode_iterator QIDI [(QI "") (HI "") (PSI "") (SI "") (DI "")]) -(define_mode_iterator HIDI [(HI "") (PSI "") (SI "") (DI "")]) (define_mode_iterator HISI [(HI "") (PSI "") (SI "")]) ;; All supported move-modes @@ -235,6 +234,12 @@ (define_code_attr mul_r_d [(zero_extend "r") (sign_extend "d")]) +;; Map RTX code to its standard insn name +(define_code_attr code_stdname + [(ashift "ashl") + (ashiftrt "ashr") + (lshiftrt "lshr") + (rotate "rotl")]) ;;======================================================================== ;; The following is used by nonlocal_goto and setjmp. @@ -2956,23 +2961,21 @@ (define_insn "*rotlqi3" [(set_attr "length" "2,4,4,1,3,5,3,0") (set_attr "cc" "set_n,set_n,clobber,none,set_n,set_n,clobber,none")]) -;; Split all rotates of HI,SI and DImode registers where rotation is by +;; Split all rotates of HI,SI and PSImode registers where rotation is by ;; a whole number of bytes. The split creates the appropriate moves and -;; considers all overlap situations. DImode is split before reload. +;; considers all overlap situations. ;; HImode does not need scratch. Use attribute for this constraint. -;; Use QI scratch for DI mode as this is often split into byte sized operands. -(define_mode_attr rotx [(DI "&r,&r,X") (SI "&r,&r,X") (PSI "&r,&r,X") (HI "X,X,X")]) -(define_mode_attr rotsmode [(DI "QI") (SI "HI") (PSI "QI") (HI "QI")]) +(define_mode_attr rotx [(SI "&r,&r,X") (PSI "&r,&r,X") (HI "X,X,X")]) +(define_mode_attr rotsmode [(SI "HI") (PSI "QI") (HI "QI")]) ;; "rotlhi3" ;; "rotlpsi3" ;; "rotlsi3" -;; "rotldi3" (define_expand "rotl3" - [(parallel [(set (match_operand:HIDI 0 "register_operand" "") - (rotate:HIDI (match_operand:HIDI 1 "register_operand" "") + [(parallel [(set (match_operand:HISI 0 "register_operand" "") + (rotate:HISI (match_operand:HISI 1 "register_operand" "") (match_operand:VOID 2 "const_int_operand" ""))) (clobber (match_dup 3))])] "" @@ -2991,9 +2994,8 @@ (define_expand "rotl3" else operands[3] = gen_rtx_SCRATCH (QImode); } - else if (mode != DImode - && (offset == 1 - || offset == GET_MODE_BITSIZE (mode) -1)) + else if (offset == 1 + || offset == GET_MODE_BITSIZE (mode) -1) { /*; Support rotate left/right by 1 */ @@ -3069,18 +3071,17 @@ (define_insn "*rotlsi2.31" ;; "*rotwhi" ;; "*rotwsi" -;; "*rotwdi" (define_insn_and_split "*rotw" - [(set (match_operand:HIDI 0 "register_operand" "=r,r,#&r") - (rotate:HIDI (match_operand:HIDI 1 "register_operand" "0,r,r") - (match_operand 2 "const_int_operand" "n,n,n"))) + [(set (match_operand:HISI 0 "register_operand" "=r,r,#&r") + (rotate:HISI (match_operand:HISI 1 "register_operand" "0,r,r") + (match_operand 2 "const_int_operand" "n,n,n"))) (clobber (match_scratch: 3 "="))] "AVR_HAVE_MOVW && CONST_INT_P (operands[2]) && GET_MODE_SIZE (mode) % 2 == 0 && 0 == INTVAL (operands[2]) % 16" "#" - "&& (reload_completed || mode == DImode)" + "&& reload_completed" [(const_int 0)] { avr_rotate_bytes (operands); @@ -3093,11 +3094,10 @@ (define_insn_and_split "*rotw" ;; "*rotbhi" ;; "*rotbpsi" ;; "*rotbsi" -;; "*rotbdi" (define_insn_and_split "*rotb" - [(set (match_operand:HIDI 0 "register_operand" "=r,r,#&r") - (rotate:HIDI (match_operand:HIDI 1 "register_operand" "0,r,r") - (match_operand 2 "const_int_operand" "n,n,n"))) + [(set (match_operand:HISI 0 "register_operand" "=r,r,#&r") + (rotate:HISI (match_operand:HISI 1 "register_operand" "0,r,r") + (match_operand 2 "const_int_operand" "n,n,n"))) (clobber (match_scratch:QI 3 "="))] "CONST_INT_P (operands[2]) && (8 == INTVAL (operands[2]) % 16 @@ -3105,7 +3105,7 @@ (define_insn_and_split "*rotb" || GET_MODE_SIZE (mode) % 2 != 0) && 0 == INTVAL (operands[2]) % 16))" "#" - "&& (reload_completed || mode == DImode)" + "&& reload_completed" [(const_int 0)] { avr_rotate_bytes (operands); @@ -5779,3 +5779,5 @@ (define_insn_and_split "*extzv.qihi2" operands[3] = simplify_gen_subreg (QImode, operands[0], HImode, 0); operands[4] = simplify_gen_subreg (QImode, operands[0], HImode, 1); }) + +(include "avr-dimode.md") Index: gcc/config/avr/avr.opt =================================================================== --- gcc/config/avr/avr.opt (revision 181554) +++ gcc/config/avr/avr.opt (working copy) @@ -77,3 +77,7 @@ When accessing RAM, use X as imposed by mbranch-cost= Target Report RejectNegative Joined UInteger Var(avr_branch_cost) Init(0) Set the cost of a branch instruction. Default value is 0. + +m64 +Target Report Var(avr_have_dimode) Init(0) +Experimental. Index: gcc/config/avr/avr-protos.h =================================================================== --- gcc/config/avr/avr-protos.h (revision 181554) +++ gcc/config/avr/avr-protos.h (working copy) @@ -56,6 +56,7 @@ extern const char *avr_out_tstsi (rtx, r extern const char *avr_out_tsthi (rtx, rtx*, int*); extern const char *avr_out_tstpsi (rtx, rtx*, int*); extern const char *avr_out_compare (rtx, rtx*, int*); +extern const char *avr_out_compare64 (rtx, rtx*, int*); extern const char *ret_cond_branch (rtx x, int len, int reverse); extern const char *avr_out_movpsi (rtx, rtx*, int*); @@ -89,6 +90,7 @@ extern const char *avr_out_sbxx_branch ( extern const char* avr_out_bitop (rtx, rtx*, int*); extern const char* avr_out_plus (rtx*, int*, int*); extern const char* avr_out_plus_noclobber (rtx*, int*, int*); +extern const char* avr_out_plus64 (rtx, int*); extern const char* avr_out_addto_sp (rtx*, int*); extern const char* avr_out_xload (rtx, rtx*, int*); extern const char* avr_out_movmem (rtx, rtx*, int*); Index: gcc/config/avr/avr.c =================================================================== --- gcc/config/avr/avr.c (revision 181592) +++ gcc/config/avr/avr.c (working copy) @@ -4031,14 +4031,17 @@ avr_out_compare (rtx insn, rtx *xop, int /* Value (0..0xff) held in clobber register xop[2] or -1 if unknown. */ int clobber_val = -1; - gcc_assert (REG_P (xreg) - && CONST_INT_P (xval)); + gcc_assert (REG_P (xreg)); + gcc_assert ((CONST_INT_P (xval) && n_bytes <= 4) + || (const_double_operand (xval, VOIDmode) && n_bytes == 8)); if (plen) *plen = 0; /* Comparisons == +/-1 and != +/-1 can be done similar to camparing - against 0 by ORing the bytes. This is one instruction shorter. */ + against 0 by ORing the bytes. This is one instruction shorter. + Notice that DImode comparisons are always against reg:DI 18 + and therefore don't use this. */ if (!test_hard_reg_class (LD_REGS, xreg) && compare_eq_p (insn) @@ -4156,6 +4159,20 @@ avr_out_compare (rtx insn, rtx *xop, int } +/* Prepare operands of compare_const_di2 to be used with avr_out_compare. */ + +const char* +avr_out_compare64 (rtx insn, rtx *op, int *plen) +{ + rtx xop[3]; + + xop[0] = gen_rtx_REG (DImode, 18); + xop[1] = op[0]; + xop[2] = op[1]; + + return avr_out_compare (insn, xop, plen); +} + /* Output test instruction for HImode. */ const char* @@ -5795,7 +5812,7 @@ avr_out_plus_1 (rtx *xop, int *plen, enu *pcc = (MINUS == code) ? CC_SET_CZN : CC_CLOBBER; if (MINUS == code) - xval = gen_int_mode (-UINTVAL (xval), mode); + xval = simplify_unary_operation (NEG, mode, xval, mode); op[2] = xop[3]; @@ -5970,6 +5987,25 @@ avr_out_plus_noclobber (rtx *xop, int *p return avr_out_plus (op, plen, pcc); } + +/* Prepare operands of adddi3_const_insn to be used with avr_out_plus_1. */ + +const char* +avr_out_plus64 (rtx addend, int *plen) +{ + int cc_dummy; + rtx op[4]; + + op[0] = gen_rtx_REG (DImode, 18); + op[1] = op[0]; + op[2] = addend; + op[3] = NULL_RTX; + + avr_out_plus_1 (op, plen, MINUS, &cc_dummy); + + return ""; +} + /* Output bit operation (IOR, AND, XOR) with register XOP[0] and compile time constant XOP[2]: @@ -6355,6 +6391,7 @@ adjust_insn_length (rtx insn, int len) case ADJUST_LEN_OUT_BITOP: avr_out_bitop (insn, op, &len); break; case ADJUST_LEN_OUT_PLUS: avr_out_plus (op, &len, NULL); break; + case ADJUST_LEN_PLUS64: avr_out_plus64 (op[0], &len); break; case ADJUST_LEN_OUT_PLUS_NOCLOBBER: avr_out_plus_noclobber (op, &len, NULL); break; @@ -6371,6 +6408,7 @@ adjust_insn_length (rtx insn, int len) case ADJUST_LEN_TSTPSI: avr_out_tstpsi (insn, op, &len); break; case ADJUST_LEN_TSTSI: avr_out_tstsi (insn, op, &len); break; case ADJUST_LEN_COMPARE: avr_out_compare (insn, op, &len); break; + case ADJUST_LEN_COMPARE64: avr_out_compare64 (insn, op, &len); break; case ADJUST_LEN_LSHRQI: lshrqi3_out (insn, op, &len); break; case ADJUST_LEN_LSHRHI: lshrhi3_out (insn, op, &len); break; @@ -8327,7 +8365,9 @@ avr_compare_pattern (rtx insn) if (pattern && NONJUMP_INSN_P (insn) && SET_DEST (pattern) == cc0_rtx - && GET_CODE (SET_SRC (pattern)) == COMPARE) + && GET_CODE (SET_SRC (pattern)) == COMPARE + && DImode != GET_MODE (XEXP (SET_SRC (pattern), 0)) + && DImode != GET_MODE (XEXP (SET_SRC (pattern), 1))) { return pattern; } Index: libgcc/config/avr/lib1funcs.S =================================================================== --- libgcc/config/avr/lib1funcs.S (revision 181554) +++ libgcc/config/avr/lib1funcs.S (working copy) @@ -1161,6 +1161,71 @@ ENDF __divdi3_moddi3 #endif /* L_divdi3 */ +.section .text.libgcc, "ax", @progbits + +#define TT __tmp_reg__ + +#if defined (L_adddi3) +;; (set (reg:DI 18) +;; (plus:DI (reg:DI 18) +;; (reg:DI 10))) +DEFUN __adddi3 + ADD A0,B0 $ adc A1,B1 $ adc A2,B2 $ adc A3,B3 + adc A4,B4 $ adc A5,B5 $ adc A6,B6 $ adc A7,B7 + ret +ENDF __adddi3 +#endif /* L_adddi3 */ + +#if defined (L_adddi3_s8) +;; (set (reg:DI 18) +;; (plus:DI (reg:DI 18) +;; (sign_extend:SI (reg:QI 26)))) +DEFUN __adddi3_s8 + clr TT + sbrc r26, 7 + com TT + ADD A0,r26 $ adc A1,TT $ adc A2,TT $ adc A3,TT + adc A4,TT $ adc A5,TT $ adc A6,TT $ adc A7,TT + ret +ENDF __adddi3_s8 +#endif /* L_adddi3_s8 */ + +#if defined (L_subdi3) +;; (set (reg:DI 18) +;; (minus:DI (reg:DI 18) +;; (reg:DI 10))) +DEFUN __subdi3 + SUB A0,B0 $ sbc A1,B1 $ sbc A2,B2 $ sbc A3,B3 + sbc A4,B4 $ sbc A5,B5 $ sbc A6,B6 $ sbc A7,B7 + ret +ENDF __subdi3 +#endif /* L_subdi3 */ + +#if defined (L_cmpdi2) +;; (set (cc0) +;; (compare (reg:DI 18) +;; (reg:DI 10))) +DEFUN __cmpdi2 + CP A0,B0 $ cpc A1,B1 $ cpc A2,B2 $ cpc A3,B3 + cpc A4,B4 $ cpc A5,B5 $ cpc A6,B6 $ cpc A7,B7 + ret +ENDF __cmpdi2 +#endif /* L_cmpdi2 */ + +#if defined (L_cmpdi2_s8) +;; (set (cc0) +;; (compare (reg:DI 18) +;; (sign_extend:SI (reg:QI 26)))) +DEFUN __cmpdi2_s8 + clr TT + sbrc r26, 7 + com TT + CP A0,r26 $ cpc A1,TT $ cpc A2,TT $ cpc A3,TT + cpc A4,TT $ cpc A5,TT $ cpc A6,TT $ cpc A7,TT + ret +ENDF __cmpdi2_s8 +#endif /* L_cmpdi2_s8 */ + #if defined (L_negdi2) DEFUN __negdi2 @@ -1174,6 +1239,8 @@ DEFUN __negdi2 ENDF __negdi2 #endif /* L_negdi2 */ +#undef TT + #undef C7 #undef C6 #undef C5 @@ -2052,6 +2119,29 @@ DEFUN __ashldi3 ENDF __ashldi3 #endif /* defined (L_ashldi3) */ +#if defined (L_rotldi3) +;; Shift left +;; r25:r18 = rotl64 (r25:r18, r17:r16) +DEFUN __rotldi3 + push r16 + andi r16, 63 + breq 2f +1: lsl r18 + rol r19 + rol r20 + rol r21 + rol r22 + rol r23 + rol r24 + rol r25 + adc r18, __zero_reg__ + dec r16 + brne 1b +2: pop r16 + ret +ENDF __rotldi3 +#endif /* defined (L_rotldi3) */ + .section .text.libgcc.fmul, "ax", @progbits Index: libgcc/config/avr/t-avr =================================================================== --- libgcc/config/avr/t-avr (revision 181554) +++ libgcc/config/avr/t-avr (working copy) @@ -47,9 +47,9 @@ LIB1ASMFUNCS = \ _popcountqi2 \ _bswapsi2 \ _bswapdi2 \ - _ashldi3 \ - _ashrdi3 \ - _lshrdi3 \ + _ashldi3 _ashrdi3 _lshrdi3 _rotldi3 \ + _adddi3 _adddi3_s8 _subdi3 \ + _cmpdi2 _cmpdi2_s8 \ _fmul _fmuls _fmulsu LIB2FUNCS_EXCLUDE = \