From patchwork Wed Dec 7 11:00:51 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: 129938 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 DB6C21007D2 for ; Wed, 7 Dec 2011 22:01:56 +1100 (EST) Received: (qmail 29146 invoked by alias); 7 Dec 2011 11:01:52 -0000 Received: (qmail 29127 invoked by uid 22791); 7 Dec 2011 11:01:49 -0000 X-SWARE-Spam-Status: No, hits=-0.3 required=5.0 tests=AWL, BAYES_00, 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; Wed, 07 Dec 2011 11:01:31 +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 (jimi mo64) (RZmta 26.10 AUTH) with ESMTPA id t05c86nB7AL12H ; Wed, 7 Dec 2011 12:00:52 +0100 (MET) Message-ID: <4EDF4763.90700@gjlay.de> Date: Wed, 07 Dec 2011 12:00:51 +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 , "Weddington, Eric" , Richard Henderson , Anatoly Sokolov Subject: Re: Ping #1: [Patch,AVR] Light-weight DImode implementation. References: <4ECAA70E.5050205@gjlay.de> <4ECAD332.9020101@redhat.com> <4ED5206D.8070408@gjlay.de> <4ED524BF.2040000@redhat.com> <8D64F155F1C88743BFDC71288E8E2DA8059850A5@csomb01.corp.atmel.com> <4ED76383.8010306@gjlay.de> In-Reply-To: <4ED76383.8010306@gjlay.de> 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 Georg-Johann Lay wrote: > Denis Chertykov wrote: > >>>>> The only question that remains is what the -m64 option should be like? >>>>> >>>>> [ ] Omit it altogether >>>>> [ ] Leave it as is (off per default) >>>>> [ ] Set it on per default >>>>> >>>>> As soon as the direction is clear, I'll post a follow-up patch to >>>>> add the missing bits like, e.g., documentation for the new switch. >>>> I'll leave the decision to Denis, but I'm for omitting it. >>> I will also defer to Denis, but I'd rather avoid having another option, >>> if we can. Keep it simple for the users. > > It might also be a hidden option like -morder2 and on per default. > Such thing is nice for developers to play :-) > >> I'm agree with Richard. I'm for omitting it. >> Denis. Here is a combined patch if that is more convenient for review. The variable avr_have_dimode that was originally set in avr.opt is still there but always set to true in avr.c. Option -m64 is omitted and thus avr.opt is unchanged. Passed without regressions. Ok? Johann gcc/ * config/avr/avr-dimode.md: New file. * config/avr/avr.md: Include it. (adjust_len): Add alternatives: plus64, compare64. (HIDI): Remove code iterator. (code_stdname): New code attribute. (rotx, rotsmode): Remove DI from interators. (rotl3, *rotw, *rotb): Use HISI instead of HIDI as code iterator. * config/avr/avr-protos.h (avr_have_dimode): New. (avr_out_plus64, avr_out_compare64): New. * config/avr/avr.c (avr_out_compare): Handle DImode. (avr_have_dimode): New variable definition and initialization. (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 182052) +++ gcc/config/avr/avr.md (working copy) @@ -142,8 +142,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, @@ -218,7 +218,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 @@ -247,6 +246,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. @@ -2968,23 +2973,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))])] "" @@ -3003,9 +3006,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 */ @@ -3081,18 +3083,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); @@ -3105,11 +3106,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 @@ -3117,7 +3117,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); @@ -5796,6 +5796,8 @@ (define_insn_and_split "*extzv.qihi1" operands[4] = simplify_gen_subreg (QImode, operands[0], HImode, 1); }) +(include "avr-dimode.md") + (define_insn_and_split "*extzv.qihi2" [(set (match_operand:HI 0 "register_operand" "=r") (zero_extend:HI Index: gcc/config/avr/avr-protos.h =================================================================== --- gcc/config/avr/avr-protos.h (revision 182051) +++ 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*); @@ -130,6 +132,8 @@ extern bool avr_xload_libgcc_p (enum mac extern void asm_output_float (FILE *file, REAL_VALUE_TYPE n); #endif +extern bool avr_have_dimode; + /* From avr-log.c */ #define avr_edump (avr_log_set_caller_e (__FUNCTION__)) Index: gcc/config/avr/avr.c =================================================================== --- gcc/config/avr/avr.c (revision 182058) +++ gcc/config/avr/avr.c (working copy) @@ -164,6 +164,9 @@ static GTY(()) section *progmem_swtable_ or to address space __pgm*. */ static GTY(()) section *progmem_section[6]; +/* Condition for insns/expanders from avr-dimode.md. */ +bool avr_have_dimode = true; + /* To track if code will use .bss and/or .data. */ bool avr_need_clear_bss_p = false; bool avr_need_copy_data_p = false; @@ -4072,14 +4075,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) @@ -4197,6 +4203,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* @@ -5836,7 +5856,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]; @@ -6011,6 +6031,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]: @@ -6396,6 +6435,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; @@ -6412,6 +6452,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; @@ -8370,7 +8411,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 182052) +++ libgcc/config/avr/lib1funcs.S (working copy) @@ -1168,6 +1168,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 @@ -1181,6 +1246,8 @@ DEFUN __negdi2 ENDF __negdi2 #endif /* L_negdi2 */ +#undef TT + #undef C7 #undef C6 #undef C5 @@ -2080,6 +2147,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 182051) +++ 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 = \