aboutsummaryrefslogtreecommitdiff
path: root/libgcc/config/avr
diff options
context:
space:
mode:
authorGeorg-Johann Lay <avr@gjlay.de>2013-02-08 10:13:37 +0000
committerGeorg-Johann Lay <gjl@gcc.gnu.org>2013-02-08 10:13:37 +0000
commit85d768f349087f3766ff84054ec7b3403c52ac7a (patch)
treec41ab849c5ffa4c56a753d5d4502a23fdc14617d /libgcc/config/avr
parent661bc682bcb87f5faa709f9bcd1679874f6652f6 (diff)
downloadgcc-85d768f349087f3766ff84054ec7b3403c52ac7a.zip
gcc-85d768f349087f3766ff84054ec7b3403c52ac7a.tar.gz
gcc-85d768f349087f3766ff84054ec7b3403c52ac7a.tar.bz2
re PR target/54222 ([avr] Implement fixed-point support)
gcc/ PR target/54222 * config/avr/avr.md (unspec) <UNSPEC_ROUND>: Add. * config/avr/avr-fixed.md (ALL4QA, ALL124QA): New mode iterators. (round<mode>3, round<mode>3_const): New expanders for fixed-mode. (*round<mode>3.libgcc): New insns for fixed-modes. * config/avr/builtins.def (ABSxx): Use a non-NULL LIBNAME. (ROUNDxx, COUNTLSxx, BITSxx, xxBITS): New DEF_BUILTINs. (ROUNDFX, COUNTLSFX, ABSFX): New DEF_BUILTINs. * config/avr/stdfix.h (absFX, bitsFX, FXbits): Remove inline implementations. Define to __builtin_avr_absFX, __builtin_avr_bitsFX, __builtin_avr_FXbits, respectively. (roundFX, countlsFX): Define to __builtin_avr_roundFX, __builtin_avr_countlsFX, respectively. * config/avr/avr-c.c (target.h): Include it. (enum avr_builtin_id): New enum. (avr_resolve_overloaded_builtin): New static function. (avr_register_target_pragmas): Use it to set targetm.resolve_overloaded_builtin. * config/avr/avr.c (avr_init_builtins): Supply myriads of local tree nodes used by DEF_BUILTIN. (avr_expand_builtin) <AVR_BUILTIN_ROUNDxx>: Sanity-check them. (avr_fold_builtin) <AVR_BUILTIN_BITSxx>: Fold to VIEW_COVERT_EXPR. <AVR_BUILTIN_xxBITS>: Same. libgcc/ PR target/54222 * config/avr/lib2funcs.c: New C sources for modules for libgcc.a. * config/avr/lib2-object.mk: New iterator to build objects from it. * config/avr/t-avr: Iterate lib2-object.mk to build objects from lib2funcs.c. (LIB2FUNCS_EXCLUDE): Add _clrsbdi2. (LIB1ASMFUNCS): Add: _ssabs_1, _mask1, _ret, _roundqq3, _rounduqq3, _round_s2, _round_u2, _round_2_const, _addmask_2, _round_s4, _round_u4, _round_4_const, _addmask_4, _round_x8, _rounddq3 _roundudq3, _roundda3 _rounduda3, _roundta3 _rounduta3. * config/avr/lib1funcs-fixed.S: Implement them. gcc/testsuite/ PR target/54222 * gcc.target/avr/torture/builtins-4-roundfx.c: New test. * gcc.target/avr/torture/builtins-5-countlsfx.c: New test. From-SVN: r195878
Diffstat (limited to 'libgcc/config/avr')
-rw-r--r--libgcc/config/avr/lib1funcs-fixed.S528
-rw-r--r--libgcc/config/avr/lib1funcs.S4
-rw-r--r--libgcc/config/avr/lib2-object.mk23
-rw-r--r--libgcc/config/avr/lib2funcs.c226
-rw-r--r--libgcc/config/avr/t-avr94
5 files changed, 867 insertions, 8 deletions
diff --git a/libgcc/config/avr/lib1funcs-fixed.S b/libgcc/config/avr/lib1funcs-fixed.S
index 731da44..92d8eaf 100644
--- a/libgcc/config/avr/lib1funcs-fixed.S
+++ b/libgcc/config/avr/lib1funcs-fixed.S
@@ -959,6 +959,28 @@ ENDF __udivusa3
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Saturation, 1 Byte
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; First Argument and Return Register
+#define A0 24
+
+#if defined (L_ssabs_1)
+DEFUN __ssabs_1
+ sbrs A0, 7
+ ret
+ neg A0
+ sbrc A0,7
+ dec A0
+ ret
+ENDF __ssabs_1
+#endif /* L_ssabs_1 */
+
+#undef A0
+
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Saturation, 2 Bytes
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -1176,3 +1198,509 @@ ENDF __sssub_8
#undef B5
#undef B6
#undef B7
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Rounding Helpers
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+#ifdef L_mask1
+
+#define AA 24
+#define CC 25
+
+;; R25 = 1 << (R24 & 7)
+;; CC = 1 << (AA & 7)
+;; Clobbers: None
+DEFUN __mask1
+ ;; CC = 2 ^ AA.1
+ ldi CC, 1 << 2
+ sbrs AA, 1
+ ldi CC, 1 << 0
+ ;; CC *= 2 ^ AA.0
+ sbrc AA, 0
+ lsl CC
+ ;; CC *= 2 ^ AA.2
+ sbrc AA, 2
+ swap CC
+ ret
+ENDF __mask1
+
+#undef AA
+#undef CC
+#endif /* L_mask1 */
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; The rounding point. Any bits smaller than
+;; 2^{-RP} will be cleared.
+#define RP R24
+
+#define A0 22
+#define A1 A0 + 1
+
+#define C0 24
+#define C1 C0 + 1
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Rounding, 1 Byte
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+#ifdef L_roundqq3
+
+;; R24 = round (R22, R24)
+;; Clobbers: R22, __tmp_reg__
+DEFUN __roundqq3
+ mov __tmp_reg__, C1
+ subi RP, __QQ_FBIT__ - 1
+ neg RP
+ ;; R25 = 1 << RP (Total offset is FBIT-1 - RP)
+ XCALL __mask1
+ mov C0, C1
+ ;; Add-Saturate 2^{-RP-1}
+ add A0, C0
+ brvc 0f
+ ldi A0, 0x7f
+0: ;; Mask out bits beyond RP
+ lsl C0
+ neg C0
+ and C0, A0
+ mov C1, __tmp_reg__
+ ret
+ENDF __roundqq3
+#endif /* L_roundqq3 */
+
+#ifdef L_rounduqq3
+
+;; R24 = round (R22, R24)
+;; Clobbers: R22, __tmp_reg__
+DEFUN __rounduqq3
+ mov __tmp_reg__, C1
+ subi RP, __UQQ_FBIT__ - 1
+ neg RP
+ ;; R25 = 1 << RP (Total offset is FBIT-1 - RP)
+ XCALL __mask1
+ mov C0, C1
+ ;; Add-Saturate 2^{-RP-1}
+ add A0, C0
+ brcc 0f
+ ldi A0, 0xff
+0: ;; Mask out bits beyond RP
+ lsl C0
+ neg C0
+ and C0, A0
+ mov C1, __tmp_reg__
+ ret
+ENDF __rounduqq3
+#endif /* L_rounduqq3 */
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Rounding, 2 Bytes
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+#ifdef L_addmask_2
+
+;; [ R25:R24 = 1 << (R24 & 15)
+;; R23:R22 += 1 << (R24 & 15) ]
+;; SREG is set according to the addition
+DEFUN __addmask_2
+ ;; R25 = 1 << (R24 & 7)
+ XCALL __mask1
+ cpi RP, 1 << 3
+ sbc C0, C0
+ ;; Swap C0 and C1 if RP.3 was set
+ and C0, C1
+ eor C1, C0
+ ;; Finally, add the power-of-two: A[] += C[]
+ add A0, C0
+ adc A1, C1
+ ret
+ENDF __addmask_2
+#endif /* L_addmask_2 */
+
+#ifdef L_round_s2
+
+;; R25:R24 = round (R23:R22, R24)
+;; Clobbers: R23, R22
+DEFUN __roundhq3
+ subi RP, __HQ_FBIT__ - __HA_FBIT__
+ENDF __roundhq3
+DEFUN __roundha3
+ subi RP, __HA_FBIT__ - 1
+ neg RP
+ ;; [ R25:R24 = 1 << (FBIT-1 - RP)
+ ;; R23:R22 += 1 << (FBIT-1 - RP) ]
+ XCALL __addmask_2
+ XJMP __round_s2_const
+ENDF __roundha3
+
+#endif /* L_round_s2 */
+
+#ifdef L_round_u2
+
+;; R25:R24 = round (R23:R22, R24)
+;; Clobbers: R23, R22
+DEFUN __rounduhq3
+ subi RP, __UHQ_FBIT__ - __UHA_FBIT__
+ENDF __rounduhq3
+DEFUN __rounduha3
+ subi RP, __UHA_FBIT__ - 1
+ neg RP
+ ;; [ R25:R24 = 1 << (FBIT-1 - RP)
+ ;; R23:R22 += 1 << (FBIT-1 - RP) ]
+ XCALL __addmask_2
+ XJMP __round_u2_const
+ENDF __rounduha3
+
+#endif /* L_round_u2 */
+
+
+#ifdef L_round_2_const
+
+;; Helpers for 2 byte wide rounding
+
+DEFUN __round_s2_const
+ brvc 2f
+ ldi A1, 0x7f
+ rjmp 1f
+ ;; FALLTHRU (Barrier)
+ENDF __round_s2_const
+
+DEFUN __round_u2_const
+ brcc 2f
+ ldi A1, 0xff
+1:
+ ldi A0, 0xff
+2:
+ ;; Saturation is performed now.
+ ;; Currently, we have C[] = 2^{-RP-1}
+ ;; C[] = 2^{-RP}
+ lsl C0
+ rol C1
+ ;;
+ NEG2 C0
+ ;; Clear the bits beyond the rounding point.
+ and C0, A0
+ and C1, A1
+ ret
+ENDF __round_u2_const
+
+#endif /* L_round_2_const */
+
+#undef A0
+#undef A1
+#undef C0
+#undef C1
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Rounding, 4 Bytes
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+#define A0 18
+#define A1 A0 + 1
+#define A2 A0 + 2
+#define A3 A0 + 3
+
+#define C0 22
+#define C1 C0 + 1
+#define C2 C0 + 2
+#define C3 C0 + 3
+
+#ifdef L_addmask_4
+
+;; [ R25:R22 = 1 << (R24 & 31)
+;; R21:R18 += 1 << (R24 & 31) ]
+;; SREG is set according to the addition
+DEFUN __addmask_4
+ ;; R25 = 1 << (R24 & 7)
+ XCALL __mask1
+ cpi RP, 1 << 4
+ sbc C0, C0
+ sbc C1, C1
+ ;; Swap C2 with C3 if RP.3 is not set
+ cpi RP, 1 << 3
+ sbc C2, C2
+ and C2, C3
+ eor C3, C2
+ ;; Swap C3:C2 with C1:C0 if RP.4 is not set
+ and C0, C2 $ eor C2, C0
+ and C1, C3 $ eor C3, C1
+ ;; Finally, add the power-of-two: A[] += C[]
+ add A0, C0
+ adc A1, C1
+ adc A2, C2
+ adc A3, C3
+ ret
+ENDF __addmask_4
+#endif /* L_addmask_4 */
+
+#ifdef L_round_s4
+
+;; R25:R22 = round (R21:R18, R24)
+;; Clobbers: R18...R21
+DEFUN __roundsq3
+ subi RP, __SQ_FBIT__ - __SA_FBIT__
+ENDF __roundsq3
+DEFUN __roundsa3
+ subi RP, __SA_FBIT__ - 1
+ neg RP
+ ;; [ R25:R22 = 1 << (FBIT-1 - RP)
+ ;; R21:R18 += 1 << (FBIT-1 - RP) ]
+ XCALL __addmask_4
+ XJMP __round_s4_const
+ENDF __roundsa3
+
+#endif /* L_round_s4 */
+
+#ifdef L_round_u4
+
+;; R25:R22 = round (R21:R18, R24)
+;; Clobbers: R18...R21
+DEFUN __roundusq3
+ subi RP, __USQ_FBIT__ - __USA_FBIT__
+ENDF __roundusq3
+DEFUN __roundusa3
+ subi RP, __USA_FBIT__ - 1
+ neg RP
+ ;; [ R25:R22 = 1 << (FBIT-1 - RP)
+ ;; R21:R18 += 1 << (FBIT-1 - RP) ]
+ XCALL __addmask_4
+ XJMP __round_u4_const
+ENDF __roundusa3
+
+#endif /* L_round_u4 */
+
+
+#ifdef L_round_4_const
+
+;; Helpers for 4 byte wide rounding
+
+DEFUN __round_s4_const
+ brvc 2f
+ ldi A3, 0x7f
+ rjmp 1f
+ ;; FALLTHRU (Barrier)
+ENDF __round_s4_const
+
+DEFUN __round_u4_const
+ brcc 2f
+ ldi A3, 0xff
+1:
+ ldi A2, 0xff
+ ldi A1, 0xff
+ ldi A0, 0xff
+2:
+ ;; Saturation is performed now.
+ ;; Currently, we have C[] = 2^{-RP-1}
+ ;; C[] = 2^{-RP}
+ lsl C0
+ rol C1
+ rol C2
+ rol C3
+ XCALL __negsi2
+ ;; Clear the bits beyond the rounding point.
+ and C0, A0
+ and C1, A1
+ and C2, A2
+ and C3, A3
+ ret
+ENDF __round_u4_const
+
+#endif /* L_round_4_const */
+
+#undef A0
+#undef A1
+#undef A2
+#undef A3
+#undef C0
+#undef C1
+#undef C2
+#undef C3
+
+#undef RP
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Rounding, 8 Bytes
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+#define RP 16
+#define FBITm1 31
+
+#define C0 18
+#define C1 C0 + 1
+#define C2 C0 + 2
+#define C3 C0 + 3
+#define C4 C0 + 4
+#define C5 C0 + 5
+#define C6 C0 + 6
+#define C7 C0 + 7
+
+#define A0 16
+#define A1 17
+#define A2 26
+#define A3 27
+#define A4 28
+#define A5 29
+#define A6 30
+#define A7 31
+
+
+#ifdef L_rounddq3
+;; R25:R18 = round (R25:R18, R16)
+;; Clobbers: ABI
+DEFUN __rounddq3
+ ldi FBITm1, __DQ_FBIT__ - 1
+ clt
+ XJMP __round_x8
+ENDF __rounddq3
+#endif /* L_rounddq3 */
+
+#ifdef L_roundudq3
+;; R25:R18 = round (R25:R18, R16)
+;; Clobbers: ABI
+DEFUN __roundudq3
+ ldi FBITm1, __UDQ_FBIT__ - 1
+ set
+ XJMP __round_x8
+ENDF __roundudq3
+#endif /* L_roundudq3 */
+
+#ifdef L_roundda3
+;; R25:R18 = round (R25:R18, R16)
+;; Clobbers: ABI
+DEFUN __roundda3
+ ldi FBITm1, __DA_FBIT__ - 1
+ clt
+ XJMP __round_x8
+ENDF __roundda3
+#endif /* L_roundda3 */
+
+#ifdef L_rounduda3
+;; R25:R18 = round (R25:R18, R16)
+;; Clobbers: ABI
+DEFUN __rounduda3
+ ldi FBITm1, __UDA_FBIT__ - 1
+ set
+ XJMP __round_x8
+ENDF __rounduda3
+#endif /* L_rounduda3 */
+
+#ifdef L_roundta3
+;; R25:R18 = round (R25:R18, R16)
+;; Clobbers: ABI
+DEFUN __roundta3
+ ldi FBITm1, __TA_FBIT__ - 1
+ clt
+ XJMP __round_x8
+ENDF __roundta3
+#endif /* L_roundta3 */
+
+#ifdef L_rounduta3
+;; R25:R18 = round (R25:R18, R16)
+;; Clobbers: ABI
+DEFUN __rounduta3
+ ldi FBITm1, __UTA_FBIT__ - 1
+ set
+ XJMP __round_x8
+ENDF __rounduta3
+#endif /* L_rounduta3 */
+
+
+#ifdef L_round_x8
+DEFUN __round_x8
+ push r16
+ push r17
+ push r28
+ push r29
+ ;; Compute log2 of addend from rounding point
+ sub RP, FBITm1
+ neg RP
+ ;; Move input to work register A[]
+ push C0
+ mov A1, C1
+ wmov A2, C2
+ wmov A4, C4
+ wmov A6, C6
+ ;; C[] = 1 << (FBIT-1 - RP)
+ XCALL __clr_8
+ inc C0
+ XCALL __ashldi3
+ pop A0
+ ;; A[] += C[]
+ add A0, C0
+ adc A1, C1
+ adc A2, C2
+ adc A3, C3
+ adc A4, C4
+ adc A5, C5
+ adc A6, C6
+ adc A7, C7
+ brts 1f
+ ;; Signed
+ brvc 3f
+ ;; Signed overflow: A[] = 0x7f...
+ brvs 2f
+1: ;; Unsigned
+ brcc 3f
+ ;; Unsigned overflow: A[] = 0xff...
+2: ldi A7, 0xff
+ ldi A6, 0xff
+ wmov A0, A6
+ wmov A2, A6
+ wmov A4, A6
+ bld A7, 7
+3:
+ ;; C[] = -C[] - C[]
+ push A0
+ ldi r16, 1
+ XCALL __ashldi3
+ pop A0
+ XCALL __negdi2
+ ;; Clear the bits beyond the rounding point.
+ and C0, A0
+ and C1, A1
+ and C2, A2
+ and C3, A3
+ and C4, A4
+ and C5, A5
+ and C6, A6
+ and C7, A7
+ ;; Epilogue
+ pop r29
+ pop r28
+ pop r17
+ pop r16
+ ret
+ENDF __round_x8
+
+#endif /* L_round_x8 */
+
+#undef A0
+#undef A1
+#undef A2
+#undef A3
+#undef A4
+#undef A5
+#undef A6
+#undef A7
+
+#undef C0
+#undef C1
+#undef C2
+#undef C3
+#undef C4
+#undef C5
+#undef C6
+#undef C7
+
+#undef RP
+#undef FBITm1
+
+
+;; Supply implementations / symbols for the bit-banging functions
+;; __builtin_avr_bitsfx and __builtin_avr_fxbits
+#ifdef L_ret
+DEFUN __ret
+ ret
+ENDF __ret
+#endif /* L_ret */
diff --git a/libgcc/config/avr/lib1funcs.S b/libgcc/config/avr/lib1funcs.S
index 9ca83a8..0a406d5 100644
--- a/libgcc/config/avr/lib1funcs.S
+++ b/libgcc/config/avr/lib1funcs.S
@@ -1684,12 +1684,12 @@ DEFUN __divdi3_moddi3
ENDF __divdi3_moddi3
+#endif /* L_divdi3 */
+
#undef R_cnt
#undef SS
#undef NN
-#endif /* L_divdi3 */
-
.section .text.libgcc, "ax", @progbits
#define TT __tmp_reg__
diff --git a/libgcc/config/avr/lib2-object.mk b/libgcc/config/avr/lib2-object.mk
new file mode 100644
index 0000000..6a9e04d
--- /dev/null
+++ b/libgcc/config/avr/lib2-object.mk
@@ -0,0 +1,23 @@
+# This file is included several times in a row, once for each element of
+# $(iter-items). On each inclusion, we advance $o to the next element.
+# $(iter-labels) and $(iter-flags) are also advanced.
+# This works similar to $(srcdir)/siditi-object.mk.
+
+o := $(firstword $(iter-items))
+iter-items := $(filter-out $o,$(iter-items))
+
+$o-label := $(firstword $(iter-labels))
+iter-labels := $(wordlist 2,$(words $(iter-labels)),$(iter-labels))
+
+$o-flag := $(firstword $(iter-flags))
+iter-flags := $(wordlist 2,$(words $(iter-flags)),$(iter-flags))
+
+$o$(objext): %$(objext): $(srcdir)/config/avr/lib2funcs.c
+ $(gcc_compile) -DL_$($*-label) -DL_LABEL=$($*-label) $($*-flag) \
+ -c $< $(vis_hide)
+
+ifeq ($(enable_shared),yes)
+$(o)_s$(objext): %_s$(objext): $(srcdir)/config/avr/lib2funcs.c
+ $(gcc_s_compile) -DL_$($*-label) -DL_LABEL=$($*-label) $($*-flag) \
+ -c $<
+endif
diff --git a/libgcc/config/avr/lib2funcs.c b/libgcc/config/avr/lib2funcs.c
new file mode 100644
index 0000000..83f2e23
--- /dev/null
+++ b/libgcc/config/avr/lib2funcs.c
@@ -0,0 +1,226 @@
+/* Copyright (C) 2013 Free Software Foundation, Inc.
+
+ 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.
+
+ Under Section 7 of GPL version 3, you are granted additional
+ permissions described in the GCC Runtime Library Exception, version
+ 3.1, as published by the Free Software Foundation.
+
+ You should have received a copy of the GNU General Public License and
+ a copy of the GCC Runtime Library Exception along with this program;
+ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+
+/* This file supplies implementations for some AVR-specific builtin
+ functions so that code like the following works as expected:
+
+ int (*f (void))(_Fract)
+ {
+ return __builtin_avr_countlsr;
+ }
+
+ In this specific case, the generated code is:
+
+ f:
+ ldi r24,lo8(gs(__countlsHI))
+ ldi r25,hi8(gs(__countlsHI))
+ ret
+*/
+
+/* Map fixed-point suffix to the corresponding fixed-point type. */
+
+typedef short _Fract fx_hr_t;
+typedef _Fract fx_r_t;
+typedef long _Fract fx_lr_t;
+typedef long long _Fract fx_llr_t;
+
+typedef unsigned short _Fract fx_uhr_t;
+typedef unsigned _Fract fx_ur_t;
+typedef unsigned long _Fract fx_ulr_t;
+typedef unsigned long long _Fract fx_ullr_t;
+
+typedef short _Accum fx_hk_t;
+typedef _Accum fx_k_t;
+typedef long _Accum fx_lk_t;
+typedef long long _Accum fx_llk_t;
+
+typedef unsigned short _Accum fx_uhk_t;
+typedef unsigned _Accum fx_uk_t;
+typedef unsigned long _Accum fx_ulk_t;
+typedef unsigned long long _Accum fx_ullk_t;
+
+/* Map fixed-point suffix to the corresponding natural integer type. */
+
+typedef char int_hr_t;
+typedef int int_r_t;
+typedef long int_lr_t;
+typedef long long int_llr_t;
+
+typedef unsigned char int_uhr_t;
+typedef unsigned int int_ur_t;
+typedef unsigned long int_ulr_t;
+typedef unsigned long long int_ullr_t;
+
+typedef int int_hk_t;
+typedef long int_k_t;
+typedef long long int_lk_t;
+typedef long long int_llk_t;
+
+typedef unsigned int int_uhk_t;
+typedef unsigned long int_uk_t;
+typedef unsigned long long int_ulk_t;
+typedef unsigned long long int_ullk_t;
+
+/* Map mode to the corresponding integer type. */
+
+typedef char int_qi_t;
+typedef int int_hi_t;
+typedef long int_si_t;
+typedef long long int_di_t;
+
+typedef unsigned char uint_qi_t;
+typedef unsigned int uint_hi_t;
+typedef unsigned long uint_si_t;
+typedef unsigned long long uint_di_t;
+
+
+
+/************************************************************************/
+
+/* Supply implementations / symbols for __builtin_roundFX ASM_NAME. */
+
+#ifdef L_round
+
+#define ROUND1(FX) \
+ ROUND2 (FX)
+
+#define ROUND2(FX) \
+ extern fx_## FX ##_t __round## FX (fx_## FX ##_t x, int rpoint); \
+ \
+ fx_## FX ##_t \
+ __round## FX (fx_## FX ##_t x, int rpoint) \
+ { \
+ return __builtin_avr_round ##FX (x, rpoint); \
+ }
+
+ROUND1(L_LABEL)
+
+#endif /* L_round */
+
+
+
+/*********************************************************************/
+
+/* Implement some count-leading-redundant-sign-bits to be used with
+ coundlsFX implementation. */
+
+#ifdef L__clrsbqi
+extern int __clrsbqi2 (char x);
+
+int
+__clrsbqi2 (char x)
+{
+ int ret;
+
+ if (x < 0)
+ x = ~x;
+
+ if (x == 0)
+ return 8 * sizeof (x) -1;
+
+ ret = __builtin_clz (x << 8);
+ return ret - 1;
+}
+#endif /* L__clrsbqi */
+
+
+#ifdef L__clrsbdi
+extern int __clrsbdi2 (long long x);
+
+int
+__clrsbdi2 (long long x)
+{
+ int ret;
+
+ if (x < 0LL)
+ x = ~x;
+
+ if (x == 0LL)
+ return 8 * sizeof (x) -1;
+
+ ret = __builtin_clzll ((unsigned long long) x);
+ return ret - 1;
+}
+#endif /* L__clrsbdi */
+
+
+
+/*********************************************************************/
+
+/* Supply implementations / symbols for __builtin_avr_countlsFX. */
+
+/* Signed */
+
+#ifdef L_countls
+
+#define COUNTLS1(MM) \
+ COUNTLS2 (MM)
+
+#define COUNTLS2(MM) \
+ extern int __countls## MM ##2 (int_## MM ##_t); \
+ extern int __clrsb## MM ##2 (int_## MM ##_t); \
+ \
+ int \
+ __countls## MM ##2 (int_## MM ##_t x) \
+ { \
+ if (x == 0) \
+ return __INT8_MAX__; \
+ \
+ return __clrsb## MM ##2 (x); \
+ }
+
+COUNTLS1(L_LABEL)
+
+#endif /* L_countls */
+
+/* Unsigned */
+
+#ifdef L_countlsu
+
+#define clz_qi2 __builtin_clz /* unused, avoid warning */
+#define clz_hi2 __builtin_clz
+#define clz_si2 __builtin_clzl
+#define clz_di2 __builtin_clzll
+
+#define COUNTLS1(MM) \
+ COUNTLS2 (MM)
+
+#define COUNTLS2(MM) \
+ extern int __countlsu## MM ##2 (uint_## MM ##_t); \
+ \
+ int \
+ __countlsu## MM ##2 (uint_## MM ##_t x) \
+ { \
+ if (x == 0) \
+ return __INT8_MAX__; \
+ \
+ if (sizeof (x) == 1) \
+ return clz_hi2 (x << 8); \
+ else \
+ return clz_## MM ##2 (x); \
+ }
+
+COUNTLS1(L_LABEL)
+
+#endif /* L_countlsu */
diff --git a/libgcc/config/avr/t-avr b/libgcc/config/avr/t-avr
index 3bc0718..a4b8113e 100644
--- a/libgcc/config/avr/t-avr
+++ b/libgcc/config/avr/t-avr
@@ -75,13 +75,24 @@ LIB1ASMFUNCS += \
_divsa3 _udivusa3 \
_clr_8 \
_ssneg_2 _ssneg_4 _ssneg_8 \
- _ssabs_2 _ssabs_4 _ssabs_8 \
+ _ssabs_1 _ssabs_2 _ssabs_4 _ssabs_8 \
_ssadd_8 _sssub_8 \
- _usadd_8 _ussub_8
+ _usadd_8 _ussub_8 \
+ _mask1 _ret \
+ _roundqq3 _rounduqq3 \
+ _round_s2 _round_u2 _round_2_const _addmask_2 \
+ _round_s4 _round_u4 _round_4_const _addmask_4 \
+ _round_x8 \
+ _rounddq3 _roundudq3 \
+ _roundda3 _rounduda3 \
+ _roundta3 _rounduta3 \
+
LIB2FUNCS_EXCLUDE = \
_moddi3 _umoddi3 \
- _clz
+ _clz \
+ _clrsbdi2 \
+
# We do not have the DF type.
# Most of the C functions in libgcc2 use almost all registers,
@@ -106,13 +117,84 @@ ifeq ($(enable_shared),yes)
libgcc-s-objects += $(patsubst %,%_s$(objext),$(hiintfuncs16))
endif
-
-# Filter out supported conversions from fixed-bit.c
-# Also filter out TQ and UTQ.
+###
conv_XY=$(conv)$(mode1)$(mode2)
func_X=$(func)$(mode)
+# Compile C functions from lib2funcs.c and add them to libgcc.a.
+#
+# Some functions which are not performance.critical are more convenient
+# to implement in C than in assembler. Most of them serve as implementation
+# for AVR-specific builtins in the case where the address of a builtin
+# function is taken or if there is no insn that implements the builtin.
+#
+# We don't use LIB2ADD because we want to iterate over the source for
+# different modes, fixed-point suffixes, etc. See iter-labels and L_LABEL.
+# iter-label will get one more underscore in order to avoid too short
+# labels like -DLk and we use -DL_k instead.
+
+# Build roundFX functions from lib2funcs.c
+
+round_suffix := hr r lr uhr ur ulr \
+ hk k uhk uk
+round_funcs := $(foreach func,_round,\
+ $(foreach mode,$(round_suffix),$(func_X)))
+
+iter-items := $(round_funcs)
+iter-labels := $(round_suffix)
+iter-flags := $(patsubst %,-DL_round,$(iter-items))
+
+include $(srcdir)/empty.mk $(patsubst %,$(srcdir)/config/avr/lib2-object.mk,$(iter-items))
+
+libgcc-objects += $(patsubst %,%$(objext),$(round_funcs))
+
+# Build clrsbXX functions from lib2funcs.c
+
+clrsb_modes := qi di
+clrsb_funcs := $(foreach func,_clrsb,\
+ $(foreach mode,$(clrsb_modes),$(func_X)))
+
+iter-items := $(clrsb_funcs)
+iter-labels := $(clrsb_funcs)
+iter-flags := $(patsubst %,-DL_clrsb,$(iter-items))
+
+include $(srcdir)/empty.mk $(patsubst %,$(srcdir)/config/avr/lib2-object.mk,$(iter-items))
+
+libgcc-objects += $(patsubst %,%$(objext),$(clrsb_funcs))
+
+# Build signed countlsFX functions from lib2funcs.c
+
+countls_modes := qi hi si di
+countls_funcs := $(foreach func,_countls,\
+ $(foreach mode,$(countls_modes),$(func_X)))
+
+iter-items := $(countls_funcs)
+iter-labels := $(countls_modes)
+iter-flags := $(patsubst %,-DL_countls,$(iter-items))
+
+include $(srcdir)/empty.mk $(patsubst %,$(srcdir)/config/avr/lib2-object.mk,$(iter-items))
+
+libgcc-objects += $(patsubst %,%$(objext),$(countls_funcs))
+
+# Build unsigned countlsFX functions from lib2funcs.c
+
+countlsu_modes := qi hi si di
+countlsu_funcs := $(foreach func,_countlsu,\
+ $(foreach mode,$(countlsu_modes),$(func_X)))
+
+iter-items := $(countlsu_funcs)
+iter-labels := $(countlsu_modes)
+iter-flags := $(patsubst %,-DL_countlsu,$(iter-items))
+
+include $(srcdir)/empty.mk $(patsubst %,$(srcdir)/config/avr/lib2-object.mk,$(iter-items))
+
+libgcc-objects += $(patsubst %,%$(objext),$(countlsu_funcs))
+
+
+# Filter out supported conversions from fixed-bit.c
+# Also filter out TQ and UTQ.
+
# Conversions supported by the compiler
convf_modes = QI UQI QQ UQQ \