Commit 8c57e547 by Georg-Johann Lay Committed by Georg-Johann Lay

Implement light-weight DImode support.

gcc/
	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.
	(rotl<mode>3, *rotw<mode>, *rotb<mode>): 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/
	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.

From-SVN: r182794
parent 5f595f16
2012-01-02 Georg-Johann Lay <avr@gjlay.de>
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.
(rotl<mode>3, *rotw<mode>, *rotb<mode>): 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 <revital.eres@linaro.org>
* ddg.c (def_has_ccmode_p): New function.
;; 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
;; <http://www.gnu.org/licenses/>.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; 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 "<code_stdname>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_<code_stdname>di3_insn ());
emit_move_insn (operands[0], acc_a);
DONE;
})
(define_insn "<code_stdname>di3_insn"
[(set (reg:DI ACC_A)
(di_shifts:DI (reg:DI ACC_A)
(reg:QI 16)))]
"avr_have_dimode"
"%~call __<code_stdname>di3"
[(set_attr "adjust_len" "call")
(set_attr "cc" "clobber")])
......@@ -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__))
......
......@@ -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;
}
......
......@@ -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 "rotl<mode>3"
[(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>mode != DImode
&& (offset == 1
|| offset == GET_MODE_BITSIZE (<MODE>mode) -1))
else if (offset == 1
|| offset == GET_MODE_BITSIZE (<MODE>mode) -1)
{
/*; Support rotate left/right by 1 */
......@@ -3207,10 +3209,9 @@
;; "*rotwhi"
;; "*rotwsi"
;; "*rotwdi"
(define_insn_and_split "*rotw<mode>"
[(set (match_operand:HIDI 0 "register_operand" "=r,r,#&r")
(rotate:HIDI (match_operand:HIDI 1 "register_operand" "0,r,r")
[(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:<rotsmode> 3 "=<rotx>"))]
"AVR_HAVE_MOVW
......@@ -3218,7 +3219,7 @@
&& GET_MODE_SIZE (<MODE>mode) % 2 == 0
&& 0 == INTVAL (operands[2]) % 16"
"#"
"&& (reload_completed || <MODE>mode == DImode)"
"&& reload_completed"
[(const_int 0)]
{
avr_rotate_bytes (operands);
......@@ -3231,10 +3232,9 @@
;; "*rotbhi"
;; "*rotbpsi"
;; "*rotbsi"
;; "*rotbdi"
(define_insn_and_split "*rotb<mode>"
[(set (match_operand:HIDI 0 "register_operand" "=r,r,#&r")
(rotate:HIDI (match_operand:HIDI 1 "register_operand" "0,r,r")
[(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 "=<rotx>"))]
"CONST_INT_P (operands[2])
......@@ -3243,7 +3243,7 @@
|| GET_MODE_SIZE (<MODE>mode) % 2 != 0)
&& 0 == INTVAL (operands[2]) % 16))"
"#"
"&& (reload_completed || <MODE>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
......
2012-01-02 Georg-Johann Lay <avr@gjlay.de>
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 <nathan@acm.org>
* libgcov.c (gcov_crc32): Remove global var.
......
......@@ -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
......
......@@ -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 = \
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment