diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 7284b31687a..9081d54022e 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,23 @@ +2012-01-02 Georg-Johann Lay + + Implement light-weight DImode support. + * 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_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. + 2012-01-02 Revital Eres * ddg.c (def_has_ccmode_p): New function. diff --git a/gcc/config/avr/avr-dimode.md b/gcc/config/avr/avr-dimode.md new file mode 100644 index 00000000000..3db069b3ad7 --- /dev/null +++ b/gcc/config/avr/avr-dimode.md @@ -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")]) diff --git a/gcc/config/avr/avr-protos.h b/gcc/config/avr/avr-protos.h index 123045181c9..09f82718ae8 100644 --- a/gcc/config/avr/avr-protos.h +++ b/gcc/config/avr/avr-protos.h @@ -56,6 +56,7 @@ extern const char *avr_out_tstsi (rtx, rtx*, int*); 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 (rtx insn, rtx operands[]); 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*); @@ -128,6 +130,8 @@ extern bool avr_xload_libgcc_p (enum machine_mode); 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__)) diff --git a/gcc/config/avr/avr.c b/gcc/config/avr/avr.c index 2493638aaec..652e41c6ae4 100644 --- a/gcc/config/avr/avr.c +++ b/gcc/config/avr/avr.c @@ -164,6 +164,9 @@ static GTY(()) section *progmem_swtable_section; 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; @@ -4091,14 +4094,17 @@ avr_out_compare (rtx insn, rtx *xop, int *plen) /* 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) @@ -4216,6 +4222,20 @@ avr_out_compare (rtx insn, rtx *xop, int *plen) } +/* 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* @@ -5855,7 +5875,7 @@ avr_out_plus_1 (rtx *xop, int *plen, enum rtx_code code, int *pcc) *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]; @@ -6030,6 +6050,25 @@ avr_out_plus_noclobber (rtx *xop, int *plen, int *pcc) 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]: @@ -6415,6 +6454,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; @@ -6431,6 +6471,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; @@ -8389,7 +8430,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; } diff --git a/gcc/config/avr/avr.md b/gcc/config/avr/avr.md index 21e329b7424..9222f0b6fff 100644 --- a/gcc/config/avr/avr.md +++ b/gcc/config/avr/avr.md @@ -142,8 +142,8 @@ ;; 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 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 @@ [(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. @@ -3094,23 +3099,21 @@ [(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))])] "" @@ -3129,9 +3132,8 @@ 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 */ @@ -3207,18 +3209,17 @@ ;; "*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); @@ -3231,11 +3232,10 @@ ;; "*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 @@ -3243,7 +3243,7 @@ || GET_MODE_SIZE (mode) % 2 != 0) && 0 == INTVAL (operands[2]) % 16))" "#" - "&& (reload_completed || mode == DImode)" + "&& reload_completed" [(const_int 0)] { avr_rotate_bytes (operands); @@ -5949,6 +5949,8 @@ 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 diff --git a/libgcc/ChangeLog b/libgcc/ChangeLog index 51cd7179c74..7c7d438ff11 100644 --- a/libgcc/ChangeLog +++ b/libgcc/ChangeLog @@ -1,3 +1,11 @@ +2012-01-02 Georg-Johann Lay + + Implement light-weight DImode support. + * 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. + 2011-12-30 Nathan Sidwell * libgcov.c (gcov_crc32): Remove global var. diff --git a/libgcc/config/avr/lib1funcs.S b/libgcc/config/avr/lib1funcs.S index bc16cf28207..f7f0865ca1f 100644 --- a/libgcc/config/avr/lib1funcs.S +++ b/libgcc/config/avr/lib1funcs.S @@ -1558,6 +1558,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 @@ -1571,6 +1636,8 @@ DEFUN __negdi2 ENDF __negdi2 #endif /* L_negdi2 */ +#undef TT + #undef C7 #undef C6 #undef C5 @@ -2470,6 +2537,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 diff --git a/libgcc/config/avr/t-avr b/libgcc/config/avr/t-avr index 7d7dc9ef33b..656816032c4 100644 --- a/libgcc/config/avr/t-avr +++ b/libgcc/config/avr/t-avr @@ -49,9 +49,9 @@ LIB1ASMFUNCS = \ _popcountqi2 \ _bswapsi2 \ _bswapdi2 \ - _ashldi3 \ - _ashrdi3 \ - _lshrdi3 \ + _ashldi3 _ashrdi3 _lshrdi3 _rotldi3 \ + _adddi3 _adddi3_s8 _subdi3 \ + _cmpdi2 _cmpdi2_s8 \ _fmul _fmuls _fmulsu LIB2FUNCS_EXCLUDE = \