diff options
Diffstat (limited to 'libgcc')
27 files changed, 2073 insertions, 216 deletions
diff --git a/libgcc/ChangeLog b/libgcc/ChangeLog index fbdd11ebf9c..0ea0ed3ad2a 100644 --- a/libgcc/ChangeLog +++ b/libgcc/ChangeLog @@ -1,3 +1,127 @@ +2012-08-24 Georg-Johann Lay <avr@gjlay.de> + + PR target/54222 + * config/avr/t-avr (conv_X): Rename to func_X. + +2012-08-24 Georg-Johann Lay <avr@gjlay.de> + + PR target/54222 + * config/avr/lib1funcs-fixed.S: New file. + * config/avr/lib1funcs.S: Include it. Undefine some divmodsi + after they are used. + (neg2, neg4): New macros. + (__mulqihi3,__umulqihi3,__mulhi3): Rewrite non-MUL variants. + (__mulhisi3,__umulhisi3,__mulsi3): Rewrite non-MUL variants. + (__umulhisi3): Speed up MUL variant if there is enough flash. + * config/avr/avr-lib.h (TA, UTA): Adjust according to gcc's + avr-modes.def. + * config/avr/t-avr (LIB1ASMFUNCS): Add: _fractqqsf, _fractuqqsf, + _fracthqsf, _fractuhqsf, _fracthasf, _fractuhasf, _fractsasf, + _fractusasf, _fractsfqq, _fractsfuqq, _fractsfhq, _fractsfuhq, + _fractsfha, _fractsfsa, _mulqq3, _muluqq3, _mulhq3, _muluhq3, + _mulha3, _muluha3, _mulsa3, _mulusa3, _divqq3, _udivuqq3, _divhq3, + _udivuhq3, _divha3, _udivuha3, _divsa3, _udivusa3. + (LIB2FUNCS_EXCLUDE): Add supported functions. + +2012-08-22 Georg-Johann Lay <avr@gjlay.de> + + * Makefile.in (fixed-funcs,fixed-conv-funcs): filter-out + LIB2FUNCS_EXCLUDE before adding them to libgcc-objects, + libgcc-s-objects. + * fixed-obj.mk: Only expand dependency if $o is not in + LIB2FUNCS_EXCLUDE. + +2012-08-22 H.J. Lu <hongjiu.lu@intel.com> + + * config/i386/t-linux (HOST_LIBGCC2_CFLAGS): New. + +2012-08-22 Joseph Myers <joseph@codesourcery.com> + + * Makefile.in (vis_hide, gen-hide-list): Do not make definitions + depend on --enable-shared. + ($(lib1asmfuncs-o)): Use %.vis files independent of + --enable-shared. + * static-object.mk ($(base)$(objext), $(base).vis) + ($(base)_s$(objext)): Use same rules for visibility handling as in + shared-object.mk. + +2012-08-21 Ian Lance Taylor <iant@google.com> + + * config/i386/morestack.S (__morestack_non_split): Increase amount + of space allocated for non-split code stack. + +2012-08-19 Joseph Myers <joseph@codesourcery.com> + + * crtstuff.c (USE_PT_GNU_EH_FRAME): Define for systems using glibc + even if inhibit_libc. + +2012-08-17 Julian Brown <julian@codesourcery.com> + + * Makefile.in (LIB2_DIVMOD_EXCEPTION_FLAGS): Default to + -fexceptions -fnon-call-exceptions if not defined. + ($(lib2-divmod-o), $(lib2-divmod-s-o)): Use above. + * config/arm/t-bpabi (LIB2_DIVMOD_EXCEPTION_FLAGS): Define. + +2012-08-17 Andreas Schwab <schwab@linux-m68k.org> + + * config/m68k/linux-atomic.c (__sync_lock_test_and_set_1): Fix + type. + +2012-08-16 David Edelsohn <dje.gcc@gmail.com> + + * config.host (*-*-aix*): Move rs6000/t-ibm-ldouble after + rs6000/t-slibgcc-aix. + +2012-08-15 Segher Boessenkool <segher@kernel.crashing.org> + + * longlong.h: (powerpc): Delete _ARCH_PWR and _ARCH_COM handling. + +2012-08-15 Segher Boessenkool <segher@kernel.crashing.org> + + * longlong.h: (whole file, powerpc): Adjust to single assembler syntax. + +2012-08-03 H.J. Lu <hongjiu.lu@intel.com> + + PR driver/54171 + * Makefile.in (version): Replace top_srcdir with srcdir. + +2012-08-03 Jonathan Yong <jon_y@users.sourceforge.net> + + * Makefile.in (version): set to BASE-VER file from gcc directory. + +2012-08-01 Nick Clifton <nickc@redhat.com> + + * config/m32c/lib2funcs.c (__clrsbhi2): New function. + Implements __clrsb for an HImode argument. + +2012-07-31 Nick Clifton <nickc@redhat.com> + + * config/stormy16/lib2funcs.c (__clrsbhi2): New function. + Implements __clrsb for an HImode argument. + * config/stormy16/clrsbhi2.c: New file: + * config/stormy16/t-stormy16 (LIB2ADD): Add clrsbhi2.c. + +2012-07-22 Steven Bosscher <steven@gcc.gnu.org> + + * libgcov.c (__gcov_ior_profiler): Benign comment fix. + +2012-07-19 Tristan Gingold <gingold@adacore.com> + Richard Henderson <rth@redhat.com> + + * unwind-seh.c: New file. + * unwind-generic.h: Include windows.h for SEH. + (_Unwind_Exception): Use 6 private fields for SEH. + (_GCC_specific_handler): Declare. + * unwind-c.c (__gcc_personality_seh0): New function. + Adjust for SEH. + * config/i386/libgcc-cygming.ver: New file. + * config/i386/t-seh-eh: New file. + * config.host (x86_64-*-mingw*): Default to seh. + +2012-07-14 Steven Bosscher <steven@gcc.gnu.org> + + * config/t-darwin (crt3.0): Remove work-around for fixed PR26840. + 2012-06-17 Uros Bizjak <ubizjak@gmail.com> * config/i386/sfp-machine.h (FP_HANDLE_EXCEPTIONS): Use diff --git a/libgcc/Makefile.in b/libgcc/Makefile.in index 22af1b40b7f..1de1b8e5a48 100644 --- a/libgcc/Makefile.in +++ b/libgcc/Makefile.in @@ -207,7 +207,7 @@ export slibdir export toolexecdir export toolexeclibdir -version := $(shell $(CC) -dumpversion) +version := $(shell cat $(srcdir)/../gcc/BASE-VER) ifeq ($(decimal_float),yes) ifeq ($(enable_decimal_float),bid) @@ -363,6 +363,7 @@ ifeq ($(enable_shared),yes) ifneq ($(LIBUNWIND),) install-libunwind = install-libunwind endif +endif # For -fvisibility=hidden. We need both a -fvisibility=hidden on # the command line, and a #define to prevent libgcc2.h etc from @@ -386,11 +387,8 @@ else gen-hide-list = echo > $@ endif -else -# Not enable_shared. +ifneq ($(enable_shared),yes) iterator = $(srcdir)/empty.mk $(patsubst %,$(srcdir)/static-object.mk,$(iter-items)) -vis_hide = -gen-hide-list = echo > \$@ endif LIB2ADD += enable-execute-stack.c @@ -439,7 +437,6 @@ LIB2_DIVMOD_FUNCS := $(filter-out $(LIB2FUNCS_EXCLUDE) $(LIB1ASMFUNCS), \ $(LIB2_DIVMOD_FUNCS)) # Build "libgcc1" (assembly) components. -ifeq ($(enable_shared),yes) lib1asmfuncs-o = $(patsubst %,%$(objext),$(LIB1ASMFUNCS)) $(lib1asmfuncs-o): %$(objext): $(srcdir)/config/$(LIB1ASMSRC) %.vis @@ -451,14 +448,9 @@ libgcc-objects += $(lib1asmfuncs-o) lib1asmfuncs-s-o = $(patsubst %,%_s$(objext),$(LIB1ASMFUNCS)) $(lib1asmfuncs-s-o): %_s$(objext): $(srcdir)/config/$(LIB1ASMSRC) $(gcc_s_compile) -DL$* -xassembler-with-cpp -c $< -libgcc-s-objects += $(lib1asmfuncs-s-o) - -else +ifeq ($(enable_shared),yes) -lib1asmfuncs-o = $(patsubst %,%$(objext),$(LIB1ASMFUNCS)) -$(lib1asmfuncs-o): %$(objext): $(srcdir)/config/$(LIB1ASMSRC) - $(gcc_compile) -DL$* -xassembler-with-cpp -c $< -libgcc-objects += $(lib1asmfuncs-o) +libgcc-s-objects += $(lib1asmfuncs-s-o) endif @@ -497,18 +489,24 @@ libgcc-s-objects += $(patsubst %,%_s$(objext),$(sifuncs) $(difuncs) $(tifuncs)) endif endif +ifeq ($(LIB2_DIVMOD_EXCEPTION_FLAGS),) +# Provide default flags for compiling divmod functions, if they haven't been +# set already by a target-specific Makefile fragment. +LIB2_DIVMOD_EXCEPTION_FLAGS := -fexceptions -fnon-call-exceptions +endif + # Build LIB2_DIVMOD_FUNCS. lib2-divmod-o = $(patsubst %,%$(objext),$(LIB2_DIVMOD_FUNCS)) $(lib2-divmod-o): %$(objext): $(srcdir)/libgcc2.c $(gcc_compile) -DL$* -c $< \ - -fexceptions -fnon-call-exceptions $(vis_hide) + $(LIB2_DIVMOD_EXCEPTION_FLAGS) $(vis_hide) libgcc-objects += $(lib2-divmod-o) ifeq ($(enable_shared),yes) lib2-divmod-s-o = $(patsubst %,%_s$(objext),$(LIB2_DIVMOD_FUNCS)) $(lib2-divmod-s-o): %_s$(objext): $(srcdir)/libgcc2.c $(gcc_s_compile) -DL$* -c $< \ - -fexceptions -fnon-call-exceptions + $(LIB2_DIVMOD_EXCEPTION_FLAGS) libgcc-s-objects += $(lib2-divmod-s-o) endif @@ -765,9 +763,9 @@ iter-to := $(fixed-modes) include $(srcdir)/empty.mk $(patsubst %,$(srcdir)/fixed-obj.mk,$(iter-items)) # Add arithmetic functions to list of objects to be built -libgcc-objects += $(patsubst %,%$(objext),$(fixed-funcs)) +libgcc-objects += $(patsubst %,%$(objext),$(filter-out $(LIB2FUNCS_EXCLUDE),$(fixed-funcs))) ifeq ($(enable_shared),yes) -libgcc-s-objects += $(patsubst %,%_s$(objext),$(fixed-funcs)) +libgcc-s-objects += $(patsubst %,%_s$(objext),$(filter-out $(LIB2FUNCS_EXCLUDE),$(fixed-funcs))) endif # Convert from or to fractional @@ -784,9 +782,9 @@ iter-to := $(fixed-conv-to) include $(srcdir)/empty.mk $(patsubst %,$(srcdir)/fixed-obj.mk,$(iter-items)) # Add conversion functions to list of objects to be built -libgcc-objects += $(patsubst %,%$(objext),$(fixed-conv-funcs)) +libgcc-objects += $(patsubst %,%$(objext),$(filter-out $(LIB2FUNCS_EXCLUDE),$(fixed-conv-funcs))) ifeq ($(enable_shared),yes) -libgcc-s-objects += $(patsubst %,%_s$(objext),$(fixed-conv-funcs)) +libgcc-s-objects += $(patsubst %,%_s$(objext),$(filter-out $(LIB2FUNCS_EXCLUDE),$(fixed-conv-funcs))) endif endif diff --git a/libgcc/config.host b/libgcc/config.host index d8ad48c5e04..d7259a77484 100644 --- a/libgcc/config.host +++ b/libgcc/config.host @@ -618,7 +618,7 @@ x86_64-*-mingw*) if test x$enable_sjlj_exceptions = xyes; then tmake_eh_file="i386/t-sjlj-eh" else - tmake_eh_file="i386/t-dw2-eh" + tmake_eh_file="i386/t-seh-eh" fi # Shared libgcc DLL install dir depends on cross/native build. if test x${build} = x${host} ; then @@ -898,15 +898,15 @@ powerpcle-*-eabi*) ;; rs6000-ibm-aix4.[3456789]* | powerpc-ibm-aix4.[3456789]*) md_unwind_header=rs6000/aix-unwind.h - tmake_file="t-fdpbit rs6000/t-ppc64-fp rs6000/t-ibm-ldouble rs6000/t-slibgcc-aix" + tmake_file="t-fdpbit rs6000/t-ppc64-fp rs6000/t-slibgcc-aix rs6000/t-ibm-ldouble" ;; rs6000-ibm-aix5.1.* | powerpc-ibm-aix5.1.*) md_unwind_header=rs6000/aix-unwind.h - tmake_file="t-fdpbit rs6000/t-ppc64-fp rs6000/t-ibm-ldouble rs6000/t-slibgcc-aix" + tmake_file="t-fdpbit rs6000/t-ppc64-fp rs6000/t-slibgcc-aix rs6000/t-ibm-ldouble" ;; rs6000-ibm-aix[56789].* | powerpc-ibm-aix[56789].*) md_unwind_header=rs6000/aix-unwind.h - tmake_file="t-fdpbit rs6000/t-ppc64-fp rs6000/t-ibm-ldouble rs6000/t-slibgcc-aix" + tmake_file="t-fdpbit rs6000/t-ppc64-fp rs6000/t-slibgcc-aix rs6000/t-ibm-ldouble" ;; rl78-*-elf) tmake_file="$tm_file t-fdpbit rl78/t-rl78" diff --git a/libgcc/config/arm/t-bpabi b/libgcc/config/arm/t-bpabi index e79cbd7064e..dddddc7c444 100644 --- a/libgcc/config/arm/t-bpabi +++ b/libgcc/config/arm/t-bpabi @@ -13,3 +13,8 @@ LIB2ADDEH = $(srcdir)/config/arm/unwind-arm.c \ # Add the BPABI names. SHLIB_MAPFILES += $(srcdir)/config/arm/libgcc-bpabi.ver + +# On ARM, specifying -fnon-call-exceptions will needlessly pull in +# the unwinder in simple programs which use 64-bit division. Omitting +# the option is safe. +LIB2_DIVMOD_EXCEPTION_FLAGS := -fexceptions diff --git a/libgcc/config/avr/avr-lib.h b/libgcc/config/avr/avr-lib.h index daca4d81f9a..66082eb8a48 100644 --- a/libgcc/config/avr/avr-lib.h +++ b/libgcc/config/avr/avr-lib.h @@ -4,3 +4,79 @@ #define DI SI typedef int QItype __attribute__ ((mode (QI))); #endif + +/* fixed-bit.h does not define functions for TA and UTA because + that part is wrapped in #if MIN_UNITS_PER_WORD > 4. + This would lead to empty functions for TA and UTA. + Thus, supply appropriate defines as if HAVE_[U]TA == 1. + #define HAVE_[U]TA 1 won't work because avr-modes.def + uses ADJUST_BYTESIZE(TA,8) and fixed-bit.h is not generic enough + to arrange for such changes of the mode size. */ + +typedef unsigned _Fract UTAtype __attribute__ ((mode (UTA))); + +#if defined (UTA_MODE) +#define FIXED_SIZE 8 /* in bytes */ +#define INT_C_TYPE UDItype +#define UINT_C_TYPE UDItype +#define HINT_C_TYPE USItype +#define HUINT_C_TYPE USItype +#define MODE_NAME UTA +#define MODE_NAME_S uta +#define MODE_UNSIGNED 1 +#endif + +#if defined (FROM_UTA) +#define FROM_TYPE 4 /* ID for fixed-point */ +#define FROM_MODE_NAME UTA +#define FROM_MODE_NAME_S uta +#define FROM_INT_C_TYPE UDItype +#define FROM_SINT_C_TYPE DItype +#define FROM_UINT_C_TYPE UDItype +#define FROM_MODE_UNSIGNED 1 +#define FROM_FIXED_SIZE 8 /* in bytes */ +#elif defined (TO_UTA) +#define TO_TYPE 4 /* ID for fixed-point */ +#define TO_MODE_NAME UTA +#define TO_MODE_NAME_S uta +#define TO_INT_C_TYPE UDItype +#define TO_SINT_C_TYPE DItype +#define TO_UINT_C_TYPE UDItype +#define TO_MODE_UNSIGNED 1 +#define TO_FIXED_SIZE 8 /* in bytes */ +#endif + +/* Same for TAmode */ + +typedef _Fract TAtype __attribute__ ((mode (TA))); + +#if defined (TA_MODE) +#define FIXED_SIZE 8 /* in bytes */ +#define INT_C_TYPE DItype +#define UINT_C_TYPE UDItype +#define HINT_C_TYPE SItype +#define HUINT_C_TYPE USItype +#define MODE_NAME TA +#define MODE_NAME_S ta +#define MODE_UNSIGNED 0 +#endif + +#if defined (FROM_TA) +#define FROM_TYPE 4 /* ID for fixed-point */ +#define FROM_MODE_NAME TA +#define FROM_MODE_NAME_S ta +#define FROM_INT_C_TYPE DItype +#define FROM_SINT_C_TYPE DItype +#define FROM_UINT_C_TYPE UDItype +#define FROM_MODE_UNSIGNED 0 +#define FROM_FIXED_SIZE 8 /* in bytes */ +#elif defined (TO_TA) +#define TO_TYPE 4 /* ID for fixed-point */ +#define TO_MODE_NAME TA +#define TO_MODE_NAME_S ta +#define TO_INT_C_TYPE DItype +#define TO_SINT_C_TYPE DItype +#define TO_UINT_C_TYPE UDItype +#define TO_MODE_UNSIGNED 0 +#define TO_FIXED_SIZE 8 /* in bytes */ +#endif diff --git a/libgcc/config/avr/lib1funcs-fixed.S b/libgcc/config/avr/lib1funcs-fixed.S new file mode 100644 index 00000000000..c1aff53d5fd --- /dev/null +++ b/libgcc/config/avr/lib1funcs-fixed.S @@ -0,0 +1,874 @@ +/* -*- Mode: Asm -*- */ +;; Copyright (C) 2012 +;; Free Software Foundation, Inc. +;; Contributed by Sean D'Epagnier (sean@depagnier.com) +;; Georg-Johann Lay (avr@gjlay.de) + +;; This file 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. + +;; In addition to the permissions in the GNU General Public License, the +;; Free Software Foundation gives you unlimited permission to link the +;; compiled version of this file into combinations with other programs, +;; and to distribute those combinations without any restriction coming +;; from the use of this file. (The General Public License restrictions +;; do apply in other respects; for example, they cover modification of +;; the file, and distribution when not linked into a combine +;; executable.) + +;; This file 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 this program; see the file COPYING. If not, write to +;; the Free Software Foundation, 51 Franklin Street, Fifth Floor, +;; Boston, MA 02110-1301, USA. + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Fixed point library routines for AVR +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +.section .text.libgcc.fixed, "ax", @progbits + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Conversions to float +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +#if defined (L_fractqqsf) +DEFUN __fractqqsf + ;; Move in place for SA -> SF conversion + clr r22 + mov r23, r24 + lsl r23 + ;; Sign-extend + sbc r24, r24 + mov r25, r24 + XJMP __fractsasf +ENDF __fractqqsf +#endif /* L_fractqqsf */ + +#if defined (L_fractuqqsf) +DEFUN __fractuqqsf + ;; Move in place for USA -> SF conversion + clr r22 + mov r23, r24 + ;; Zero-extend + clr r24 + clr r25 + XJMP __fractusasf +ENDF __fractuqqsf +#endif /* L_fractuqqsf */ + +#if defined (L_fracthqsf) +DEFUN __fracthqsf + ;; Move in place for SA -> SF conversion + wmov 22, 24 + lsl r22 + rol r23 + ;; Sign-extend + sbc r24, r24 + mov r25, r24 + XJMP __fractsasf +ENDF __fracthqsf +#endif /* L_fracthqsf */ + +#if defined (L_fractuhqsf) +DEFUN __fractuhqsf + ;; Move in place for USA -> SF conversion + wmov 22, 24 + ;; Zero-extend + clr r24 + clr r25 + XJMP __fractusasf +ENDF __fractuhqsf +#endif /* L_fractuhqsf */ + +#if defined (L_fracthasf) +DEFUN __fracthasf + ;; Move in place for SA -> SF conversion + clr r22 + mov r23, r24 + mov r24, r25 + ;; Sign-extend + lsl r25 + sbc r25, r25 + XJMP __fractsasf +ENDF __fracthasf +#endif /* L_fracthasf */ + +#if defined (L_fractuhasf) +DEFUN __fractuhasf + ;; Move in place for USA -> SF conversion + clr r22 + mov r23, r24 + mov r24, r25 + ;; Zero-extend + clr r25 + XJMP __fractusasf +ENDF __fractuhasf +#endif /* L_fractuhasf */ + + +#if defined (L_fractsqsf) +DEFUN __fractsqsf + XCALL __floatsisf + ;; Divide non-zero results by 2^31 to move the + ;; decimal point into place + tst r25 + breq 0f + subi r24, exp_lo (31) + sbci r25, exp_hi (31) +0: ret +ENDF __fractsqsf +#endif /* L_fractsqsf */ + +#if defined (L_fractusqsf) +DEFUN __fractusqsf + XCALL __floatunsisf + ;; Divide non-zero results by 2^32 to move the + ;; decimal point into place + cpse r25, __zero_reg__ + subi r25, exp_hi (32) + ret +ENDF __fractusqsf +#endif /* L_fractusqsf */ + +#if defined (L_fractsasf) +DEFUN __fractsasf + XCALL __floatsisf + ;; Divide non-zero results by 2^16 to move the + ;; decimal point into place + cpse r25, __zero_reg__ + subi r25, exp_hi (16) + ret +ENDF __fractsasf +#endif /* L_fractsasf */ + +#if defined (L_fractusasf) +DEFUN __fractusasf + XCALL __floatunsisf + ;; Divide non-zero results by 2^16 to move the + ;; decimal point into place + cpse r25, __zero_reg__ + subi r25, exp_hi (16) + ret +ENDF __fractusasf +#endif /* L_fractusasf */ + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Conversions from float +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +#if defined (L_fractsfqq) +DEFUN __fractsfqq + ;; Multiply with 2^{24+7} to get a QQ result in r25 + subi r24, exp_lo (-31) + sbci r25, exp_hi (-31) + XCALL __fixsfsi + mov r24, r25 + ret +ENDF __fractsfqq +#endif /* L_fractsfqq */ + +#if defined (L_fractsfuqq) +DEFUN __fractsfuqq + ;; Multiply with 2^{24+8} to get a UQQ result in r25 + subi r25, exp_hi (-32) + XCALL __fixunssfsi + mov r24, r25 + ret +ENDF __fractsfuqq +#endif /* L_fractsfuqq */ + +#if defined (L_fractsfha) +DEFUN __fractsfha + ;; Multiply with 2^24 to get a HA result in r25:r24 + subi r25, exp_hi (-24) + XJMP __fixsfsi +ENDF __fractsfha +#endif /* L_fractsfha */ + +#if defined (L_fractsfuha) +DEFUN __fractsfuha + ;; Multiply with 2^24 to get a UHA result in r25:r24 + subi r25, exp_hi (-24) + XJMP __fixunssfsi +ENDF __fractsfuha +#endif /* L_fractsfuha */ + +#if defined (L_fractsfhq) +DEFUN __fractsfsq +ENDF __fractsfsq + +DEFUN __fractsfhq + ;; Multiply with 2^{16+15} to get a HQ result in r25:r24 + ;; resp. with 2^31 to get a SQ result in r25:r22 + subi r24, exp_lo (-31) + sbci r25, exp_hi (-31) + XJMP __fixsfsi +ENDF __fractsfhq +#endif /* L_fractsfhq */ + +#if defined (L_fractsfuhq) +DEFUN __fractsfusq +ENDF __fractsfusq + +DEFUN __fractsfuhq + ;; Multiply with 2^{16+16} to get a UHQ result in r25:r24 + ;; resp. with 2^32 to get a USQ result in r25:r22 + subi r25, exp_hi (-32) + XJMP __fixunssfsi +ENDF __fractsfuhq +#endif /* L_fractsfuhq */ + +#if defined (L_fractsfsa) +DEFUN __fractsfsa + ;; Multiply with 2^16 to get a SA result in r25:r22 + subi r25, exp_hi (-16) + XJMP __fixsfsi +ENDF __fractsfsa +#endif /* L_fractsfsa */ + +#if defined (L_fractsfusa) +DEFUN __fractsfusa + ;; Multiply with 2^16 to get a USA result in r25:r22 + subi r25, exp_hi (-16) + XJMP __fixunssfsi +ENDF __fractsfusa +#endif /* L_fractsfusa */ + + +;; For multiplication the functions here are called directly from +;; avr-fixed.md instead of using the standard libcall mechanisms. +;; This can make better code because GCC knows exactly which +;; of the call-used registers (not all of them) are clobbered. */ + +/******************************************************* + Fractional Multiplication 8 x 8 without MUL +*******************************************************/ + +#if defined (L_mulqq3) && !defined (__AVR_HAVE_MUL__) +;;; R23 = R24 * R25 +;;; Clobbers: __tmp_reg__, R22, R24, R25 +;;; Rounding: ??? +DEFUN __mulqq3 + XCALL __fmuls + ;; TR 18037 requires that (-1) * (-1) does not overflow + ;; The only input that can produce -1 is (-1)^2. + dec r23 + brvs 0f + inc r23 +0: ret +ENDF __mulqq3 +#endif /* L_mulqq3 && ! HAVE_MUL */ + +/******************************************************* + Fractional Multiply .16 x .16 with and without MUL +*******************************************************/ + +#if defined (L_mulhq3) +;;; Same code with and without MUL, but the interfaces differ: +;;; no MUL: (R25:R24) = (R22:R23) * (R24:R25) +;;; Clobbers: ABI, called by optabs +;;; MUL: (R25:R24) = (R19:R18) * (R27:R26) +;;; Clobbers: __tmp_reg__, R22, R23 +;;; Rounding: -0.5 LSB <= error <= 0.5 LSB +DEFUN __mulhq3 + XCALL __mulhisi3 + ;; Shift result into place + lsl r23 + rol r24 + rol r25 + brvs 1f + ;; Round + sbrc r23, 7 + adiw r24, 1 + ret +1: ;; Overflow. TR 18037 requires (-1)^2 not to overflow + ldi r24, lo8 (0x7fff) + ldi r25, hi8 (0x7fff) + ret +ENDF __mulhq3 +#endif /* defined (L_mulhq3) */ + +#if defined (L_muluhq3) +;;; Same code with and without MUL, but the interfaces differ: +;;; no MUL: (R25:R24) *= (R23:R22) +;;; Clobbers: ABI, called by optabs +;;; MUL: (R25:R24) = (R19:R18) * (R27:R26) +;;; Clobbers: __tmp_reg__, R22, R23 +;;; Rounding: -0.5 LSB < error <= 0.5 LSB +DEFUN __muluhq3 + XCALL __umulhisi3 + ;; Round + sbrc r23, 7 + adiw r24, 1 + ret +ENDF __muluhq3 +#endif /* L_muluhq3 */ + + +/******************************************************* + Fixed Multiply 8.8 x 8.8 with and without MUL +*******************************************************/ + +#if defined (L_mulha3) +;;; Same code with and without MUL, but the interfaces differ: +;;; no MUL: (R25:R24) = (R22:R23) * (R24:R25) +;;; Clobbers: ABI, called by optabs +;;; MUL: (R25:R24) = (R19:R18) * (R27:R26) +;;; Clobbers: __tmp_reg__, R22, R23 +;;; Rounding: -0.5 LSB <= error <= 0.5 LSB +DEFUN __mulha3 + XCALL __mulhisi3 + XJMP __muluha3_round +ENDF __mulha3 +#endif /* L_mulha3 */ + +#if defined (L_muluha3) +;;; Same code with and without MUL, but the interfaces differ: +;;; no MUL: (R25:R24) *= (R23:R22) +;;; Clobbers: ABI, called by optabs +;;; MUL: (R25:R24) = (R19:R18) * (R27:R26) +;;; Clobbers: __tmp_reg__, R22, R23 +;;; Rounding: -0.5 LSB < error <= 0.5 LSB +DEFUN __muluha3 + XCALL __umulhisi3 + XJMP __muluha3_round +ENDF __muluha3 +#endif /* L_muluha3 */ + +#if defined (L_muluha3_round) +DEFUN __muluha3_round + ;; Shift result into place + mov r25, r24 + mov r24, r23 + ;; Round + sbrc r22, 7 + adiw r24, 1 + ret +ENDF __muluha3_round +#endif /* L_muluha3_round */ + + +/******************************************************* + Fixed Multiplication 16.16 x 16.16 +*******************************************************/ + +#if defined (__AVR_HAVE_MUL__) + +;; Multiplier +#define A0 16 +#define A1 A0+1 +#define A2 A1+1 +#define A3 A2+1 + +;; Multiplicand +#define B0 20 +#define B1 B0+1 +#define B2 B1+1 +#define B3 B2+1 + +;; Result +#define C0 24 +#define C1 C0+1 +#define C2 C1+1 +#define C3 C2+1 + +#if defined (L_mulusa3) +;;; (C3:C0) = (A3:A0) * (B3:B0) +;;; Clobbers: __tmp_reg__ +;;; Rounding: -0.5 LSB < error <= 0.5 LSB +DEFUN __mulusa3 + ;; Some of the MUL instructions have LSBs outside the result. + ;; Don't ignore these LSBs in order to tame rounding error. + ;; Use C2/C3 for these LSBs. + + clr C0 + clr C1 + mul A0, B0 $ movw C2, r0 + + mul A1, B0 $ add C3, r0 $ adc C0, r1 + mul A0, B1 $ add C3, r0 $ adc C0, r1 $ rol C1 + + ;; Round + sbrc C3, 7 + adiw C0, 1 + + ;; The following MULs don't have LSBs outside the result. + ;; C2/C3 is the high part. + + mul A0, B2 $ add C0, r0 $ adc C1, r1 $ sbc C2, C2 + mul A1, B1 $ add C0, r0 $ adc C1, r1 $ sbci C2, 0 + mul A2, B0 $ add C0, r0 $ adc C1, r1 $ sbci C2, 0 + neg C2 + + mul A0, B3 $ add C1, r0 $ adc C2, r1 $ sbc C3, C3 + mul A1, B2 $ add C1, r0 $ adc C2, r1 $ sbci C3, 0 + mul A2, B1 $ add C1, r0 $ adc C2, r1 $ sbci C3, 0 + mul A3, B0 $ add C1, r0 $ adc C2, r1 $ sbci C3, 0 + neg C3 + + mul A1, B3 $ add C2, r0 $ adc C3, r1 + mul A2, B2 $ add C2, r0 $ adc C3, r1 + mul A3, B1 $ add C2, r0 $ adc C3, r1 + + mul A2, B3 $ add C3, r0 + mul A3, B2 $ add C3, r0 + + clr __zero_reg__ + ret +ENDF __mulusa3 +#endif /* L_mulusa3 */ + +#if defined (L_mulsa3) +;;; (C3:C0) = (A3:A0) * (B3:B0) +;;; Clobbers: __tmp_reg__ +;;; Rounding: -0.5 LSB <= error <= 0.5 LSB +DEFUN __mulsa3 + XCALL __mulusa3 + tst B3 + brpl 1f + sub C2, A0 + sbc C3, A1 +1: sbrs A3, 7 + ret + sub C2, B0 + sbc C3, B1 + ret +ENDF __mulsa3 +#endif /* L_mulsa3 */ + +#undef A0 +#undef A1 +#undef A2 +#undef A3 +#undef B0 +#undef B1 +#undef B2 +#undef B3 +#undef C0 +#undef C1 +#undef C2 +#undef C3 + +#else /* __AVR_HAVE_MUL__ */ + +#define A0 18 +#define A1 A0+1 +#define A2 A0+2 +#define A3 A0+3 + +#define B0 22 +#define B1 B0+1 +#define B2 B0+2 +#define B3 B0+3 + +#define C0 22 +#define C1 C0+1 +#define C2 C0+2 +#define C3 C0+3 + +;; __tmp_reg__ +#define CC0 0 +;; __zero_reg__ +#define CC1 1 +#define CC2 16 +#define CC3 17 + +#define AA0 26 +#define AA1 AA0+1 +#define AA2 30 +#define AA3 AA2+1 + +#if defined (L_mulsa3) +;;; (R25:R22) *= (R21:R18) +;;; Clobbers: ABI, called by optabs +;;; Rounding: -1 LSB <= error <= 1 LSB +DEFUN __mulsa3 + push B0 + push B1 + bst B3, 7 + XCALL __mulusa3 + ;; A survived in 31:30:27:26 + rcall 1f + pop AA1 + pop AA0 + bst AA3, 7 +1: brtc 9f + ;; 1-extend A/B + sub C2, AA0 + sbc C3, AA1 +9: ret +ENDF __mulsa3 +#endif /* L_mulsa3 */ + +#if defined (L_mulusa3) +;;; (R25:R22) *= (R21:R18) +;;; Clobbers: ABI, called by optabs and __mulsua +;;; Rounding: -1 LSB <= error <= 1 LSB +;;; Does not clobber T and A[] survives in 26, 27, 30, 31 +DEFUN __mulusa3 + push CC2 + push CC3 + ; clear result + clr __tmp_reg__ + wmov CC2, CC0 + ; save multiplicand + wmov AA0, A0 + wmov AA2, A2 + rjmp 3f + + ;; Loop the integral part + +1: ;; CC += A * 2^n; n >= 0 + add CC0,A0 $ adc CC1,A1 $ adc CC2,A2 $ adc CC3,A3 + +2: ;; A <<= 1 + lsl A0 $ rol A1 $ rol A2 $ rol A3 + +3: ;; IBIT(B) >>= 1 + ;; Carry = n-th bit of B; n >= 0 + lsr B3 + ror B2 + brcs 1b + sbci B3, 0 + brne 2b + + ;; Loop the fractional part + ;; B2/B3 is 0 now, use as guard bits for rounding + ;; Restore multiplicand + wmov A0, AA0 + wmov A2, AA2 + rjmp 5f + +4: ;; CC += A:Guard * 2^n; n < 0 + add B3,B2 $ adc CC0,A0 $ adc CC1,A1 $ adc CC2,A2 $ adc CC3,A3 +5: + ;; A:Guard >>= 1 + lsr A3 $ ror A2 $ ror A1 $ ror A0 $ ror B2 + + ;; FBIT(B) <<= 1 + ;; Carry = n-th bit of B; n < 0 + lsl B0 + rol B1 + brcs 4b + sbci B0, 0 + brne 5b + + ;; Move result into place and round + lsl B3 + wmov C2, CC2 + wmov C0, CC0 + clr __zero_reg__ + adc C0, __zero_reg__ + adc C1, __zero_reg__ + adc C2, __zero_reg__ + adc C3, __zero_reg__ + + ;; Epilogue + pop CC3 + pop CC2 + ret +ENDF __mulusa3 +#endif /* L_mulusa3 */ + +#undef A0 +#undef A1 +#undef A2 +#undef A3 +#undef B0 +#undef B1 +#undef B2 +#undef B3 +#undef C0 +#undef C1 +#undef C2 +#undef C3 +#undef AA0 +#undef AA1 +#undef AA2 +#undef AA3 +#undef CC0 +#undef CC1 +#undef CC2 +#undef CC3 + +#endif /* __AVR_HAVE_MUL__ */ + +/******************************************************* + Fractional Division 8 / 8 +*******************************************************/ + +#define r_divd r25 /* dividend */ +#define r_quo r24 /* quotient */ +#define r_div r22 /* divisor */ + +#if defined (L_divqq3) +DEFUN __divqq3 + mov r0, r_divd + eor r0, r_div + sbrc r_div, 7 + neg r_div + sbrc r_divd, 7 + neg r_divd + cp r_divd, r_div + breq __divqq3_minus1 ; if equal return -1 + XCALL __udivuqq3 + lsr r_quo + sbrc r0, 7 ; negate result if needed + neg r_quo + ret +__divqq3_minus1: + ldi r_quo, 0x80 + ret +ENDF __divqq3 +#endif /* defined (L_divqq3) */ + +#if defined (L_udivuqq3) +DEFUN __udivuqq3 + clr r_quo ; clear quotient + inc __zero_reg__ ; init loop counter, used per shift +__udivuqq3_loop: + lsl r_divd ; shift dividend + brcs 0f ; dividend overflow + cp r_divd,r_div ; compare dividend & divisor + brcc 0f ; dividend >= divisor + rol r_quo ; shift quotient (with CARRY) + rjmp __udivuqq3_cont +0: + sub r_divd,r_div ; restore dividend + lsl r_quo ; shift quotient (without CARRY) +__udivuqq3_cont: + lsl __zero_reg__ ; shift loop-counter bit + brne __udivuqq3_loop + com r_quo ; complement result + ; because C flag was complemented in loop + ret +ENDF __udivuqq3 +#endif /* defined (L_udivuqq3) */ + +#undef r_divd +#undef r_quo +#undef r_div + + +/******************************************************* + Fractional Division 16 / 16 +*******************************************************/ +#define r_divdL 26 /* dividend Low */ +#define r_divdH 27 /* dividend Hig */ +#define r_quoL 24 /* quotient Low */ +#define r_quoH 25 /* quotient High */ +#define r_divL 22 /* divisor */ +#define r_divH 23 /* divisor */ +#define r_cnt 21 + +#if defined (L_divhq3) +DEFUN __divhq3 + mov r0, r_divdH + eor r0, r_divH + sbrs r_divH, 7 + rjmp 1f + NEG2 r_divL +1: + sbrs r_divdH, 7 + rjmp 2f + NEG2 r_divdL +2: + cp r_divdL, r_divL + cpc r_divdH, r_divH + breq __divhq3_minus1 ; if equal return -1 + XCALL __udivuhq3 + lsr r_quoH + ror r_quoL + brpl 9f + ;; negate result if needed + NEG2 r_quoL +9: + ret +__divhq3_minus1: + ldi r_quoH, 0x80 + clr r_quoL + ret +ENDF __divhq3 +#endif /* defined (L_divhq3) */ + +#if defined (L_udivuhq3) +DEFUN __udivuhq3 + sub r_quoH,r_quoH ; clear quotient and carry + ;; FALLTHRU +ENDF __udivuhq3 + +DEFUN __udivuha3_common + clr r_quoL ; clear quotient + ldi r_cnt,16 ; init loop counter +__udivuhq3_loop: + rol r_divdL ; shift dividend (with CARRY) + rol r_divdH + brcs __udivuhq3_ep ; dividend overflow + cp r_divdL,r_divL ; compare dividend & divisor + cpc r_divdH,r_divH + brcc __udivuhq3_ep ; dividend >= divisor + rol r_quoL ; shift quotient (with CARRY) + rjmp __udivuhq3_cont +__udivuhq3_ep: + sub r_divdL,r_divL ; restore dividend + sbc r_divdH,r_divH + lsl r_quoL ; shift quotient (without CARRY) +__udivuhq3_cont: + rol r_quoH ; shift quotient + dec r_cnt ; decrement loop counter + brne __udivuhq3_loop + com r_quoL ; complement result + com r_quoH ; because C flag was complemented in loop + ret +ENDF __udivuha3_common +#endif /* defined (L_udivuhq3) */ + +/******************************************************* + Fixed Division 8.8 / 8.8 +*******************************************************/ +#if defined (L_divha3) +DEFUN __divha3 + mov r0, r_divdH + eor r0, r_divH + sbrs r_divH, 7 + rjmp 1f + NEG2 r_divL +1: + sbrs r_divdH, 7 + rjmp 2f + NEG2 r_divdL +2: + XCALL __udivuha3 + sbrs r0, 7 ; negate result if needed + ret + NEG2 r_quoL + ret +ENDF __divha3 +#endif /* defined (L_divha3) */ + +#if defined (L_udivuha3) +DEFUN __udivuha3 + mov r_quoH, r_divdL + mov r_divdL, r_divdH + clr r_divdH + lsl r_quoH ; shift quotient into carry + XJMP __udivuha3_common ; same as fractional after rearrange +ENDF __udivuha3 +#endif /* defined (L_udivuha3) */ + +#undef r_divdL +#undef r_divdH +#undef r_quoL +#undef r_quoH +#undef r_divL +#undef r_divH +#undef r_cnt + +/******************************************************* + Fixed Division 16.16 / 16.16 +*******************************************************/ + +#define r_arg1L 24 /* arg1 gets passed already in place */ +#define r_arg1H 25 +#define r_arg1HL 26 +#define r_arg1HH 27 +#define r_divdL 26 /* dividend Low */ +#define r_divdH 27 +#define r_divdHL 30 +#define r_divdHH 31 /* dividend High */ +#define r_quoL 22 /* quotient Low */ +#define r_quoH 23 +#define r_quoHL 24 +#define r_quoHH 25 /* quotient High */ +#define r_divL 18 /* divisor Low */ +#define r_divH 19 +#define r_divHL 20 +#define r_divHH 21 /* divisor High */ +#define r_cnt __zero_reg__ /* loop count (0 after the loop!) */ + +#if defined (L_divsa3) +DEFUN __divsa3 + mov r0, r_arg1HH + eor r0, r_divHH + sbrs r_divHH, 7 + rjmp 1f + NEG4 r_divL +1: + sbrs r_arg1HH, 7 + rjmp 2f + NEG4 r_arg1L +2: + XCALL __udivusa3 + sbrs r0, 7 ; negate result if needed + ret + NEG4 r_quoL + ret +ENDF __divsa3 +#endif /* defined (L_divsa3) */ + +#if defined (L_udivusa3) +DEFUN __udivusa3 + ldi r_divdHL, 32 ; init loop counter + mov r_cnt, r_divdHL + clr r_divdHL + clr r_divdHH + wmov r_quoL, r_divdHL + lsl r_quoHL ; shift quotient into carry + rol r_quoHH +__udivusa3_loop: + rol r_divdL ; shift dividend (with CARRY) + rol r_divdH + rol r_divdHL + rol r_divdHH + brcs __udivusa3_ep ; dividend overflow + cp r_divdL,r_divL ; compare dividend & divisor + cpc r_divdH,r_divH + cpc r_divdHL,r_divHL + cpc r_divdHH,r_divHH + brcc __udivusa3_ep ; dividend >= divisor + rol r_quoL ; shift quotient (with CARRY) + rjmp __udivusa3_cont +__udivusa3_ep: + sub r_divdL,r_divL ; restore dividend + sbc r_divdH,r_divH + sbc r_divdHL,r_divHL + sbc r_divdHH,r_divHH + lsl r_quoL ; shift quotient (without CARRY) +__udivusa3_cont: + rol r_quoH ; shift quotient + rol r_quoHL + rol r_quoHH + dec r_cnt ; decrement loop counter + brne __udivusa3_loop + com r_quoL ; complement result + com r_quoH ; because C flag was complemented in loop + com r_quoHL + com r_quoHH + ret +ENDF __udivusa3 +#endif /* defined (L_udivusa3) */ + +#undef r_arg1L +#undef r_arg1H +#undef r_arg1HL +#undef r_arg1HH +#undef r_divdL +#undef r_divdH +#undef r_divdHL +#undef r_divdHH +#undef r_quoL +#undef r_quoH +#undef r_quoHL +#undef r_quoHH +#undef r_divL +#undef r_divH +#undef r_divHL +#undef r_divHH +#undef r_cnt diff --git a/libgcc/config/avr/lib1funcs.S b/libgcc/config/avr/lib1funcs.S index 95a7d3d4eeb..6b9879ee7d7 100644 --- a/libgcc/config/avr/lib1funcs.S +++ b/libgcc/config/avr/lib1funcs.S @@ -91,6 +91,35 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see .endfunc .endm +;; Negate a 2-byte value held in consecutive registers +.macro NEG2 reg + com \reg+1 + neg \reg + sbci \reg+1, -1 +.endm + +;; Negate a 4-byte value held in consecutive registers +.macro NEG4 reg + com \reg+3 + com \reg+2 + com \reg+1 +.if \reg >= 16 + neg \reg + sbci \reg+1, -1 + sbci \reg+2, -1 + sbci \reg+3, -1 +.else + com \reg + adc \reg, __zero_reg__ + adc \reg+1, __zero_reg__ + adc \reg+2, __zero_reg__ + adc \reg+3, __zero_reg__ +.endif +.endm + +#define exp_lo(N) hlo8 ((N) << 23) +#define exp_hi(N) hhi8 ((N) << 23) + .section .text.libgcc.mul, "ax", @progbits @@ -126,175 +155,246 @@ ENDF __mulqi3 #endif /* defined (L_mulqi3) */ -#if defined (L_mulqihi3) -DEFUN __mulqihi3 - clr r25 - sbrc r24, 7 - dec r25 - clr r23 - sbrc r22, 7 - dec r22 - XJMP __mulhi3 -ENDF __mulqihi3: -#endif /* defined (L_mulqihi3) */ + +/******************************************************* + Widening Multiplication 16 = 8 x 8 without MUL + Multiplication 16 x 16 without MUL +*******************************************************/ + +#define A0 r22 +#define A1 r23 +#define B0 r24 +#define BB0 r20 +#define B1 r25 +;; Output overlaps input, thus expand result in CC0/1 +#define C0 r24 +#define C1 r25 +#define CC0 __tmp_reg__ +#define CC1 R21 #if defined (L_umulqihi3) +;;; R25:R24 = (unsigned int) R22 * (unsigned int) R24 +;;; (C1:C0) = (unsigned int) A0 * (unsigned int) B0 +;;; Clobbers: __tmp_reg__, R21..R23 DEFUN __umulqihi3 - clr r25 - clr r23 - XJMP __mulhi3 + clr A1 + clr B1 + XJMP __mulhi3 ENDF __umulqihi3 -#endif /* defined (L_umulqihi3) */ +#endif /* L_umulqihi3 */ -/******************************************************* - Multiplication 16 x 16 without MUL -*******************************************************/ -#if defined (L_mulhi3) -#define r_arg1L r24 /* multiplier Low */ -#define r_arg1H r25 /* multiplier High */ -#define r_arg2L r22 /* multiplicand Low */ -#define r_arg2H r23 /* multiplicand High */ -#define r_resL __tmp_reg__ /* result Low */ -#define r_resH r21 /* result High */ +#if defined (L_mulqihi3) +;;; R25:R24 = (signed int) R22 * (signed int) R24 +;;; (C1:C0) = (signed int) A0 * (signed int) B0 +;;; Clobbers: __tmp_reg__, R20..R23 +DEFUN __mulqihi3 + ;; Sign-extend B0 + clr B1 + sbrc B0, 7 + com B1 + ;; The multiplication runs twice as fast if A1 is zero, thus: + ;; Zero-extend A0 + clr A1 +#ifdef __AVR_HAVE_JMP_CALL__ + ;; Store B0 * sign of A + clr BB0 + sbrc A0, 7 + mov BB0, B0 + call __mulhi3 +#else /* have no CALL */ + ;; Skip sign-extension of A if A >= 0 + ;; Same size as with the first alternative but avoids errata skip + ;; and is faster if A >= 0 + sbrs A0, 7 + rjmp __mulhi3 + ;; If A < 0 store B + mov BB0, B0 + rcall __mulhi3 +#endif /* HAVE_JMP_CALL */ + ;; 1-extend A after the multiplication + sub C1, BB0 + ret +ENDF __mulqihi3 +#endif /* L_mulqihi3 */ +#if defined (L_mulhi3) +;;; R25:R24 = R23:R22 * R25:R24 +;;; (C1:C0) = (A1:A0) * (B1:B0) +;;; Clobbers: __tmp_reg__, R21..R23 DEFUN __mulhi3 - clr r_resH ; clear result - clr r_resL ; clear result -__mulhi3_loop: - sbrs r_arg1L,0 - rjmp __mulhi3_skip1 - add r_resL,r_arg2L ; result + multiplicand - adc r_resH,r_arg2H -__mulhi3_skip1: - add r_arg2L,r_arg2L ; shift multiplicand - adc r_arg2H,r_arg2H - - cp r_arg2L,__zero_reg__ - cpc r_arg2H,__zero_reg__ - breq __mulhi3_exit ; while multiplicand != 0 - - lsr r_arg1H ; gets LSB of multiplier - ror r_arg1L - sbiw r_arg1L,0 - brne __mulhi3_loop ; exit if multiplier = 0 -__mulhi3_exit: - mov r_arg1H,r_resH ; result to return register - mov r_arg1L,r_resL - ret -ENDF __mulhi3 -#undef r_arg1L -#undef r_arg1H -#undef r_arg2L -#undef r_arg2H -#undef r_resL -#undef r_resH + ;; Clear result + clr CC0 + clr CC1 + rjmp 3f +1: + ;; Bit n of A is 1 --> C += B << n + add CC0, B0 + adc CC1, B1 +2: + lsl B0 + rol B1 +3: + ;; If B == 0 we are ready + sbiw B0, 0 + breq 9f + + ;; Carry = n-th bit of A + lsr A1 + ror A0 + ;; If bit n of A is set, then go add B * 2^n to C + brcs 1b + + ;; Carry = 0 --> The ROR above acts like CP A0, 0 + ;; Thus, it is sufficient to CPC the high part to test A against 0 + cpc A1, __zero_reg__ + ;; Only proceed if A != 0 + brne 2b +9: + ;; Move Result into place + mov C0, CC0 + mov C1, CC1 + ret +ENDF __mulhi3 +#endif /* L_mulhi3 */ -#endif /* defined (L_mulhi3) */ +#undef A0 +#undef A1 +#undef B0 +#undef BB0 +#undef B1 +#undef C0 +#undef C1 +#undef CC0 +#undef CC1 + + +#define A0 22 +#define A1 A0+1 +#define A2 A0+2 +#define A3 A0+3 + +#define B0 18 +#define B1 B0+1 +#define B2 B0+2 +#define B3 B0+3 + +#define CC0 26 +#define CC1 CC0+1 +#define CC2 30 +#define CC3 CC2+1 + +#define C0 22 +#define C1 C0+1 +#define C2 C0+2 +#define C3 C0+3 /******************************************************* Widening Multiplication 32 = 16 x 16 without MUL *******************************************************/ -#if defined (L_mulhisi3) -DEFUN __mulhisi3 -;;; FIXME: This is dead code (noone calls it) - mov_l r18, r24 - mov_h r19, r25 - clr r24 - sbrc r23, 7 - dec r24 - mov r25, r24 - clr r20 - sbrc r19, 7 - dec r20 - mov r21, r20 - XJMP __mulsi3 -ENDF __mulhisi3 -#endif /* defined (L_mulhisi3) */ - #if defined (L_umulhisi3) DEFUN __umulhisi3 -;;; FIXME: This is dead code (noone calls it) - mov_l r18, r24 - mov_h r19, r25 - clr r24 - clr r25 - mov_l r20, r24 - mov_h r21, r25 + wmov B0, 24 + ;; Zero-extend B + clr B2 + clr B3 + ;; Zero-extend A + wmov A2, B2 XJMP __mulsi3 ENDF __umulhisi3 -#endif /* defined (L_umulhisi3) */ +#endif /* L_umulhisi3 */ + +#if defined (L_mulhisi3) +DEFUN __mulhisi3 + wmov B0, 24 + ;; Sign-extend B + lsl r25 + sbc B2, B2 + mov B3, B2 +#ifdef __AVR_ERRATA_SKIP_JMP_CALL__ + ;; Sign-extend A + clr A2 + sbrc A1, 7 + com A2 + mov A3, A2 + XJMP __mulsi3 +#else /* no __AVR_ERRATA_SKIP_JMP_CALL__ */ + ;; Zero-extend A and __mulsi3 will run at least twice as fast + ;; compared to a sign-extended A. + clr A2 + clr A3 + sbrs A1, 7 + XJMP __mulsi3 + ;; If A < 0 then perform the B * 0xffff.... before the + ;; very multiplication by initializing the high part of the + ;; result CC with -B. + wmov CC2, A2 + sub CC2, B0 + sbc CC3, B1 + XJMP __mulsi3_helper +#endif /* __AVR_ERRATA_SKIP_JMP_CALL__ */ +ENDF __mulhisi3 +#endif /* L_mulhisi3 */ + -#if defined (L_mulsi3) /******************************************************* Multiplication 32 x 32 without MUL *******************************************************/ -#define r_arg1L r22 /* multiplier Low */ -#define r_arg1H r23 -#define r_arg1HL r24 -#define r_arg1HH r25 /* multiplier High */ - -#define r_arg2L r18 /* multiplicand Low */ -#define r_arg2H r19 -#define r_arg2HL r20 -#define r_arg2HH r21 /* multiplicand High */ - -#define r_resL r26 /* result Low */ -#define r_resH r27 -#define r_resHL r30 -#define r_resHH r31 /* result High */ +#if defined (L_mulsi3) DEFUN __mulsi3 - clr r_resHH ; clear result - clr r_resHL ; clear result - clr r_resH ; clear result - clr r_resL ; clear result -__mulsi3_loop: - sbrs r_arg1L,0 - rjmp __mulsi3_skip1 - add r_resL,r_arg2L ; result + multiplicand - adc r_resH,r_arg2H - adc r_resHL,r_arg2HL - adc r_resHH,r_arg2HH -__mulsi3_skip1: - add r_arg2L,r_arg2L ; shift multiplicand - adc r_arg2H,r_arg2H - adc r_arg2HL,r_arg2HL - adc r_arg2HH,r_arg2HH - - lsr r_arg1HH ; gets LSB of multiplier - ror r_arg1HL - ror r_arg1H - ror r_arg1L - brne __mulsi3_loop - sbiw r_arg1HL,0 - cpc r_arg1H,r_arg1L - brne __mulsi3_loop ; exit if multiplier = 0 -__mulsi3_exit: - mov_h r_arg1HH,r_resHH ; result to return register - mov_l r_arg1HL,r_resHL - mov_h r_arg1H,r_resH - mov_l r_arg1L,r_resL - ret -ENDF __mulsi3 + ;; Clear result + clr CC2 + clr CC3 + ;; FALLTHRU +ENDF __mulsi3 -#undef r_arg1L -#undef r_arg1H -#undef r_arg1HL -#undef r_arg1HH - -#undef r_arg2L -#undef r_arg2H -#undef r_arg2HL -#undef r_arg2HH - -#undef r_resL -#undef r_resH -#undef r_resHL -#undef r_resHH +DEFUN __mulsi3_helper + clr CC0 + clr CC1 + rjmp 3f + +1: ;; If bit n of A is set, then add B * 2^n to the result in CC + ;; CC += B + add CC0,B0 $ adc CC1,B1 $ adc CC2,B2 $ adc CC3,B3 + +2: ;; B <<= 1 + lsl B0 $ rol B1 $ rol B2 $ rol B3 + +3: ;; A >>= 1: Carry = n-th bit of A + lsr A3 $ ror A2 $ ror A1 $ ror A0 + + brcs 1b + ;; Only continue if A != 0 + sbci A1, 0 + brne 2b + sbiw A2, 0 + brne 2b + + ;; All bits of A are consumed: Copy result to return register C + wmov C0, CC0 + wmov C2, CC2 + ret +ENDF __mulsi3_helper +#endif /* L_mulsi3 */ -#endif /* defined (L_mulsi3) */ +#undef A0 +#undef A1 +#undef A2 +#undef A3 +#undef B0 +#undef B1 +#undef B2 +#undef B3 +#undef C0 +#undef C1 +#undef C2 +#undef C3 +#undef CC0 +#undef CC1 +#undef CC2 +#undef CC3 #endif /* !defined (__AVR_HAVE_MUL__) */ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -316,7 +416,7 @@ ENDF __mulsi3 #define C3 C0+3 /******************************************************* - Widening Multiplication 32 = 16 x 16 + Widening Multiplication 32 = 16 x 16 with MUL *******************************************************/ #if defined (L_mulhisi3) @@ -364,7 +464,17 @@ DEFUN __umulhisi3 mul A1, B1 movw C2, r0 mul A0, B1 +#ifdef __AVR_HAVE_JMP_CALL__ + ;; This function is used by many other routines, often multiple times. + ;; Therefore, if the flash size is not too limited, avoid the RCALL + ;; and inverst 6 Bytes to speed things up. + add C1, r0 + adc C2, r1 + clr __zero_reg__ + adc C3, __zero_reg__ +#else rcall 1f +#endif mul A1, B0 1: add C1, r0 adc C2, r1 @@ -375,7 +485,7 @@ ENDF __umulhisi3 #endif /* L_umulhisi3 */ /******************************************************* - Widening Multiplication 32 = 16 x 32 + Widening Multiplication 32 = 16 x 32 with MUL *******************************************************/ #if defined (L_mulshisi3) @@ -425,7 +535,7 @@ ENDF __muluhisi3 #endif /* L_muluhisi3 */ /******************************************************* - Multiplication 32 x 32 + Multiplication 32 x 32 with MUL *******************************************************/ #if defined (L_mulsi3) @@ -468,7 +578,7 @@ ENDF __mulsi3 #endif /* __AVR_HAVE_MUL__ */ /******************************************************* - Multiplication 24 x 24 + Multiplication 24 x 24 with MUL *******************************************************/ #if defined (L_mulpsi3) @@ -1247,6 +1357,19 @@ __divmodsi4_exit: ENDF __divmodsi4 #endif /* defined (L_divmodsi4) */ +#undef r_remHH +#undef r_remHL +#undef r_remH +#undef r_remL +#undef r_arg1HH +#undef r_arg1HL +#undef r_arg1H +#undef r_arg1L +#undef r_arg2HH +#undef r_arg2HL +#undef r_arg2H +#undef r_arg2L +#undef r_cnt /******************************************************* Division 64 / 64 @@ -2757,9 +2880,7 @@ DEFUN __fmulsu_exit XJMP __fmul 1: XCALL __fmul ;; C = -C iff A0.7 = 1 - com C1 - neg C0 - sbci C1, -1 + NEG2 C0 ret ENDF __fmulsu_exit #endif /* L_fmulsu */ @@ -2794,3 +2915,5 @@ ENDF __fmul #undef B1 #undef C0 #undef C1 + +#include "lib1funcs-fixed.S" diff --git a/libgcc/config/avr/t-avr b/libgcc/config/avr/t-avr index 43caa94ca2a..749613376b3 100644 --- a/libgcc/config/avr/t-avr +++ b/libgcc/config/avr/t-avr @@ -2,6 +2,7 @@ LIB1ASMSRC = avr/lib1funcs.S LIB1ASMFUNCS = \ _mulqi3 \ _mulhi3 \ + _mulqihi3 _umulqihi3 \ _mulpsi3 _mulsqipsi3 \ _mulhisi3 \ _umulhisi3 \ @@ -55,6 +56,24 @@ LIB1ASMFUNCS = \ _cmpdi2 _cmpdi2_s8 \ _fmul _fmuls _fmulsu +# Fixed point routines in avr/lib1funcs-fixed.S +LIB1ASMFUNCS += \ + _fractqqsf _fractuqqsf \ + _fracthqsf _fractuhqsf _fracthasf _fractuhasf \ + _fractsasf _fractusasf _fractsqsf _fractusqsf \ + \ + _fractsfqq _fractsfuqq \ + _fractsfhq _fractsfuhq _fractsfha _fractsfuha \ + _fractsfsa _fractsfusa \ + _mulqq3 \ + _mulhq3 _muluhq3 \ + _mulha3 _muluha3 _muluha3_round \ + _mulsa3 _mulusa3 \ + _divqq3 _udivuqq3 \ + _divhq3 _udivuhq3 \ + _divha3 _udivuha3 \ + _divsa3 _udivusa3 + LIB2FUNCS_EXCLUDE = \ _moddi3 _umoddi3 \ _clz @@ -81,3 +100,49 @@ libgcc-objects += $(patsubst %,%$(objext),$(hiintfuncs16)) ifeq ($(enable_shared),yes) libgcc-s-objects += $(patsubst %,%_s$(objext),$(hiintfuncs16)) endif + + +# Filter out supported conversions from fixed-bit.c + +conv_XY=$(conv)$(mode1)$(mode2) +func_X=$(func)$(mode) + +# Conversions supported by the compiler + +convf_modes = QI UQI QQ UQQ \ + HI UHI HQ UHQ HA UHA \ + SI USI SQ USQ SA USA \ + DI UDI DQ UDQ DA UDA \ + TI UTI TQ UTQ TA UTA + +LIB2FUNCS_EXCLUDE += \ + $(foreach conv,_fract _fractuns,\ + $(foreach mode1,$(convf_modes),\ + $(foreach mode2,$(convf_modes),$(conv_XY)))) + +# Conversions supported by lib1funcs-fixed.S + +conv_to_sf_modes = QQ UQQ HQ UHQ HA UHA SQ USQ SA USA +conv_from_sf_modes = QQ UQQ HQ UHQ HA UHA SA USA + +LIB2FUNCS_EXCLUDE += \ + $(foreach conv,_fract, \ + $(foreach mode1,$(conv_to_sf_modes), \ + $(foreach mode2,SF,$(conv_XY)))) + +LIB2FUNCS_EXCLUDE += \ + $(foreach conv,_fract,\ + $(foreach mode1,SF,\ + $(foreach mode2,$(conv_from_sf_modes),$(conv_XY)))) + +# Arithmetik supported by the compiler + +allfix_modes = QQ UQQ HQ UHQ HA UHA SQ USQ SA USA DA UDA DQ UDQ TQ UTQ TA UTA + +LIB2FUNCS_EXCLUDE += \ + $(foreach func,_add _sub,\ + $(foreach mode,$(allfix_modes),$(func_X)3)) + +LIB2FUNCS_EXCLUDE += \ + $(foreach func,_lshr _ashl _ashr _cmp,\ + $(foreach mode,$(allfix_modes),$(func_X))) diff --git a/libgcc/config/i386/libgcc-cygming.ver b/libgcc/config/i386/libgcc-cygming.ver new file mode 100644 index 00000000000..8966cfb5322 --- /dev/null +++ b/libgcc/config/i386/libgcc-cygming.ver @@ -0,0 +1,22 @@ +# Copyright (C) 2012 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. +# +# 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/>. + +GCC_4.8 { + _GCC_specific_handler + __gcc_personality_seh0 +} diff --git a/libgcc/config/i386/morestack.S b/libgcc/config/i386/morestack.S index 228d6901abd..9528431f7e6 100644 --- a/libgcc/config/i386/morestack.S +++ b/libgcc/config/i386/morestack.S @@ -83,6 +83,9 @@ #endif +# The amount of space we ask for when calling non-split-stack code. +#define NON_SPLIT_STACK 0x100000 + # This entry point is for split-stack code which calls non-split-stack # code. When the linker sees this case, it converts the call to # __morestack to call __morestack_non_split instead. We just bump the @@ -109,7 +112,7 @@ __morestack_non_split: movl %esp,%eax # Current stack, subl 8(%esp),%eax # less required stack frame size, - subl $0x4000,%eax # less space for non-split code. + subl $NON_SPLIT_STACK,%eax # less space for non-split code. cmpl %gs:0x30,%eax # See if we have enough space. jb 2f # Get more space if we need it. @@ -171,7 +174,8 @@ __morestack_non_split: .cfi_adjust_cfa_offset -4 # Account for popped register. - addl $0x5000+BACKOFF,4(%esp) # Increment space we request. + # Increment space we request. + addl $NON_SPLIT_STACK+0x1000+BACKOFF,4(%esp) # Fall through into morestack. @@ -186,7 +190,7 @@ __morestack_non_split: movq %rsp,%rax # Current stack, subq %r10,%rax # less required stack frame size, - subq $0x4000,%rax # less space for non-split code. + subq $NON_SPLIT_STACK,%rax # less space for non-split code. #ifdef __LP64__ cmpq %fs:0x70,%rax # See if we have enough space. @@ -219,7 +223,8 @@ __morestack_non_split: .cfi_adjust_cfa_offset -8 # Adjust for popped register. - addq $0x5000+BACKOFF,%r10 # Increment space we request. + # Increment space we request. + addq $NON_SPLIT_STACK+0x1000+BACKOFF,%r10 # Fall through into morestack. diff --git a/libgcc/config/i386/t-linux b/libgcc/config/i386/t-linux index 29b4c223983..4f47f7bfa59 100644 --- a/libgcc/config/i386/t-linux +++ b/libgcc/config/i386/t-linux @@ -2,3 +2,5 @@ # Need to support TImode for x86. Override the settings from # t-slibgcc-elf-ver and t-linux SHLIB_MAPFILES = libgcc-std.ver $(srcdir)/config/i386/libgcc-glibc.ver + +HOST_LIBGCC2_CFLAGS += -mlong-double-80 diff --git a/libgcc/config/i386/t-seh-eh b/libgcc/config/i386/t-seh-eh new file mode 100644 index 00000000000..066ca54b010 --- /dev/null +++ b/libgcc/config/i386/t-seh-eh @@ -0,0 +1,6 @@ + +# We are using SEH EH. +EH_MODEL = seh + +# Use SEH exception handling. +LIB2ADDEH = $(srcdir)/unwind-seh.c $(srcdir)/unwind-sjlj.c $(srcdir)/unwind-c.c diff --git a/libgcc/config/i386/t-slibgcc-cygming b/libgcc/config/i386/t-slibgcc-cygming index 3bee8b98084..6236c78e466 100644 --- a/libgcc/config/i386/t-slibgcc-cygming +++ b/libgcc/config/i386/t-slibgcc-cygming @@ -55,4 +55,4 @@ SHLIB_MKMAP = $(srcdir)/mkmap-flat.awk # We'd like to use SHLIB_SONAME here too, but shlib_base_name # does not get substituted before mkmap-flat.awk is run. SHLIB_MKMAP_OPTS = -v pe_dll=libgcc_s_$(EH_MODEL)-$(SHLIB_SOVERSION)$(SHLIB_EXT) -SHLIB_MAPFILES = libgcc-std.ver +SHLIB_MAPFILES = libgcc-std.ver $(srcdir)/config/i386/libgcc-cygming.ver diff --git a/libgcc/config/m32c/lib2funcs.c b/libgcc/config/m32c/lib2funcs.c index 274affc4ab0..76b237cdf26 100644 --- a/libgcc/config/m32c/lib2funcs.c +++ b/libgcc/config/m32c/lib2funcs.c @@ -1,5 +1,5 @@ /* libgcc routines for R8C/M16C/M32C - Copyright (C) 2005, 2009 + Copyright (C) 2005, 2009, 2012 Free Software Foundation, Inc. Contributed by Red Hat. @@ -132,3 +132,17 @@ __umoddi3 (uint32_type a, uint32_type b) { return udivmodsi4 (a, b, 1); } + +/* Returns the number of leading redundant sign bits in X. + I.e. the number of bits following the most significant bit which are + identical to it. There are no special cases for 0 or other values. */ + +int +__clrsbhi2 (word_type x) +{ + if (x < 0) + x = ~x; + if (x == 0) + return 15; + return __builtin_clz (x) - 1; +} diff --git a/libgcc/config/m68k/linux-atomic.c b/libgcc/config/m68k/linux-atomic.c index 6e81d6b5d5e..a2bba596d53 100644 --- a/libgcc/config/m68k/linux-atomic.c +++ b/libgcc/config/m68k/linux-atomic.c @@ -1,5 +1,5 @@ /* Linux-specific atomic operations for m68k Linux. - Copyright (C) 2011 Free Software Foundation, Inc. + Copyright (C) 2011, 2012 Free Software Foundation, Inc. Based on code contributed by CodeSourcery for ARM EABI Linux. This file is part of GCC. @@ -207,5 +207,5 @@ SUBWORD_BOOL_CAS (unsigned char, 1) #define COMMA , WORD_SYNC_OP (test_and_set, , COMMA, oldval) -SUBWORD_SYNC_OP (test_and_set, , COMMA, unsigned short, 1, oldval) +SUBWORD_SYNC_OP (test_and_set, , COMMA, unsigned char, 1, oldval) SUBWORD_SYNC_OP (test_and_set, , COMMA, unsigned short, 2, oldval) diff --git a/libgcc/config/stormy16/clrsbhi2.c b/libgcc/config/stormy16/clrsbhi2.c new file mode 100644 index 00000000000..3ce41aca061 --- /dev/null +++ b/libgcc/config/stormy16/clrsbhi2.c @@ -0,0 +1,2 @@ +#define XSTORMY16_CLRSBHI2 +#include "lib2funcs.c" diff --git a/libgcc/config/stormy16/lib2funcs.c b/libgcc/config/stormy16/lib2funcs.c index a10a9b28119..a996fd15e24 100644 --- a/libgcc/config/stormy16/lib2funcs.c +++ b/libgcc/config/stormy16/lib2funcs.c @@ -311,6 +311,22 @@ __ffshi2 (UHWtype u) } #endif +#ifdef XSTORMY16_CLRSBHI2 +/* Returns the number of leading redundant sign bits in X. + I.e. the number of bits following the most significant bit which are + identical to it. There are no special cases for 0 or other values. */ + +int +__clrsbhi2 (HWtype x) +{ + if (x < 0) + x = ~x; + if (x == 0) + return 15; + return __builtin_clz (x) - 1; +} +#endif + #ifdef XSTORMY16_UCMPSI2 /* Performs an unsigned comparison of two 32-bit values: A and B. If A is less than B, then 0 is returned. If A is greater than B, diff --git a/libgcc/config/stormy16/t-stormy16 b/libgcc/config/stormy16/t-stormy16 index d62d167d93d..48ded89d3bf 100644 --- a/libgcc/config/stormy16/t-stormy16 +++ b/libgcc/config/stormy16/t-stormy16 @@ -33,6 +33,7 @@ LIB2ADD = \ $(srcdir)/config/stormy16/clzhi2.c \ $(srcdir)/config/stormy16/ctzhi2.c \ $(srcdir)/config/stormy16/ffshi2.c \ + $(srcdir)/config/stormy16/clrsbhi2.c \ $(srcdir)/config/stormy16/cmpsi2.c \ $(srcdir)/config/stormy16/ucmpsi2.c diff --git a/libgcc/config/t-darwin b/libgcc/config/t-darwin index 3365f010225..a69169fa610 100644 --- a/libgcc/config/t-darwin +++ b/libgcc/config/t-darwin @@ -1,7 +1,5 @@ -# Pass -fno-tree-dominator-opts to work around bug 26840. crt3.o: $(srcdir)/config/darwin-crt3.c - $(crt_compile) \ - -fno-tree-dominator-opts $(DARWIN_EXTRA_CRT_BUILD_CFLAGS) -c $< + $(crt_compile) $(DARWIN_EXTRA_CRT_BUILD_CFLAGS) -c $< crttms.o: $(srcdir)/config/darwin-crt-tm.c $(crt_compile) $(DARWIN_EXTRA_CRT_BUILD_CFLAGS) -DSTART -c $< diff --git a/libgcc/crtstuff.c b/libgcc/crtstuff.c index 5d820fa45ac..973956ac322 100644 --- a/libgcc/crtstuff.c +++ b/libgcc/crtstuff.c @@ -1,7 +1,7 @@ /* Specialized bits of code needed to support construction and destruction of file-scope objects in C++ code. Copyright (C) 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 - 2002, 2003, 2004, 2005, 2006, 2007, 2009, 2010, 2011 + 2002, 2003, 2004, 2005, 2006, 2007, 2009, 2010, 2011, 2012 Free Software Foundation, Inc. Contributed by Ron Guilmette (rfg@monkeys.com). @@ -113,6 +113,20 @@ call_ ## FUNC (void) \ # define USE_PT_GNU_EH_FRAME # endif #endif + +#if defined(OBJECT_FORMAT_ELF) \ + && !defined(OBJECT_FORMAT_FLAT) \ + && defined(HAVE_LD_EH_FRAME_HDR) \ + && !defined(CRTSTUFFT_O) \ + && defined(inhibit_libc) \ + && (defined(__GLIBC__) || defined(__gnu_linux__) || defined(__GNU__)) +/* On systems using glibc, an inhibit_libc build of libgcc is only + part of a bootstrap process. Build the same crt*.o as would be + built with headers present, so that it is not necessary to build + glibc more than once for the bootstrap to converge. */ +# define USE_PT_GNU_EH_FRAME +#endif + #if defined(EH_FRAME_SECTION_NAME) && !defined(USE_PT_GNU_EH_FRAME) # define USE_EH_FRAME_REGISTRY #endif diff --git a/libgcc/fixed-obj.mk b/libgcc/fixed-obj.mk index ac699d2f9e3..4db7a5792c7 100644 --- a/libgcc/fixed-obj.mk +++ b/libgcc/fixed-obj.mk @@ -22,6 +22,7 @@ endif #$(info $o$(objext): -DL$($o-label) $($o-opt)) +ifneq ($o,$(filter $o,$(LIB2FUNCS_EXCLUDE))) $o$(objext): %$(objext): $(srcdir)/fixed-bit.c $(gcc_compile) -DL$($*-label) $($*-opt) -c $(srcdir)/fixed-bit.c $(vis_hide) @@ -29,3 +30,4 @@ ifeq ($(enable_shared),yes) $(o)_s$(objext): %_s$(objext): $(srcdir)/fixed-bit.c $(gcc_s_compile) -DL$($*-label) $($*-opt) -c $(srcdir)/fixed-bit.c endif +endif diff --git a/libgcc/libgcov.c b/libgcc/libgcov.c index 8ed897117f7..a22e8f4c3ee 100644 --- a/libgcc/libgcov.c +++ b/libgcc/libgcov.c @@ -1040,8 +1040,7 @@ __gcov_average_profiler (gcov_type *counters, gcov_type value) #endif #ifdef L_gcov_ior_profiler -/* Increase corresponding COUNTER by VALUE. FIXME: Perhaps we want - to saturate up. */ +/* Bitwise-OR VALUE into COUNTER. */ void __gcov_ior_profiler (gcov_type *counters, gcov_type value) diff --git a/libgcc/longlong.h b/libgcc/longlong.h index 04277183963..30e638ca131 100644 --- a/libgcc/longlong.h +++ b/libgcc/longlong.h @@ -850,8 +850,6 @@ UDItype __umulsidi3 (USItype, USItype); FIXME: What's needed for gcc PowerPC VxWorks? __vxworks__ is not good enough, since that hits ARM and m68k too. */ #if (defined (_ARCH_PPC) /* AIX */ \ - || defined (_ARCH_PWR) /* AIX */ \ - || defined (_ARCH_COM) /* AIX */ \ || defined (__powerpc__) /* gcc */ \ || defined (__POWERPC__) /* BEOS */ \ || defined (__ppc__) /* Darwin */ \ @@ -862,37 +860,37 @@ UDItype __umulsidi3 (USItype, USItype); #define add_ssaaaa(sh, sl, ah, al, bh, bl) \ do { \ if (__builtin_constant_p (bh) && (bh) == 0) \ - __asm__ ("{a%I4|add%I4c} %1,%3,%4\n\t{aze|addze} %0,%2" \ + __asm__ ("add%I4c %1,%3,%4\n\taddze %0,%2" \ : "=r" (sh), "=&r" (sl) : "r" (ah), "%r" (al), "rI" (bl));\ else if (__builtin_constant_p (bh) && (bh) == ~(USItype) 0) \ - __asm__ ("{a%I4|add%I4c} %1,%3,%4\n\t{ame|addme} %0,%2" \ + __asm__ ("add%I4c %1,%3,%4\n\taddme %0,%2" \ : "=r" (sh), "=&r" (sl) : "r" (ah), "%r" (al), "rI" (bl));\ else \ - __asm__ ("{a%I5|add%I5c} %1,%4,%5\n\t{ae|adde} %0,%2,%3" \ + __asm__ ("add%I5c %1,%4,%5\n\tadde %0,%2,%3" \ : "=r" (sh), "=&r" (sl) \ : "%r" (ah), "r" (bh), "%r" (al), "rI" (bl)); \ } while (0) #define sub_ddmmss(sh, sl, ah, al, bh, bl) \ do { \ if (__builtin_constant_p (ah) && (ah) == 0) \ - __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{sfze|subfze} %0,%2" \ + __asm__ ("subf%I3c %1,%4,%3\n\tsubfze %0,%2" \ : "=r" (sh), "=&r" (sl) : "r" (bh), "rI" (al), "r" (bl));\ else if (__builtin_constant_p (ah) && (ah) == ~(USItype) 0) \ - __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{sfme|subfme} %0,%2" \ + __asm__ ("subf%I3c %1,%4,%3\n\tsubfme %0,%2" \ : "=r" (sh), "=&r" (sl) : "r" (bh), "rI" (al), "r" (bl));\ else if (__builtin_constant_p (bh) && (bh) == 0) \ - __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{ame|addme} %0,%2" \ + __asm__ ("subf%I3c %1,%4,%3\n\taddme %0,%2" \ : "=r" (sh), "=&r" (sl) : "r" (ah), "rI" (al), "r" (bl));\ else if (__builtin_constant_p (bh) && (bh) == ~(USItype) 0) \ - __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{aze|addze} %0,%2" \ + __asm__ ("subf%I3c %1,%4,%3\n\taddze %0,%2" \ : "=r" (sh), "=&r" (sl) : "r" (ah), "rI" (al), "r" (bl));\ else \ - __asm__ ("{sf%I4|subf%I4c} %1,%5,%4\n\t{sfe|subfe} %0,%3,%2" \ + __asm__ ("subf%I4c %1,%5,%4\n\tsubfe %0,%3,%2" \ : "=r" (sh), "=&r" (sl) \ : "r" (ah), "r" (bh), "rI" (al), "r" (bl)); \ } while (0) #define count_leading_zeros(count, x) \ - __asm__ ("{cntlz|cntlzw} %0,%1" : "=r" (count) : "r" (x)) + __asm__ ("cntlzw %0,%1" : "=r" (count) : "r" (x)) #define COUNT_LEADING_ZEROS_0 32 #if defined (_ARCH_PPC) || defined (__powerpc__) || defined (__POWERPC__) \ || defined (__ppc__) \ @@ -914,14 +912,6 @@ UDItype __umulsidi3 (USItype, USItype); } while (0) #define SMUL_TIME 14 #define UDIV_TIME 120 -#elif defined (_ARCH_PWR) -#define UMUL_TIME 8 -#define smul_ppmm(xh, xl, m0, m1) \ - __asm__ ("mul %0,%2,%3" : "=r" (xh), "=q" (xl) : "r" (m0), "r" (m1)) -#define SMUL_TIME 4 -#define sdiv_qrnnd(q, r, nh, nl, d) \ - __asm__ ("div %0,%2,%4" : "=r" (q), "=q" (r) : "r" (nh), "1" (nl), "r" (d)) -#define UDIV_TIME 100 #endif #endif /* 32-bit POWER architecture variants. */ @@ -931,32 +921,32 @@ UDItype __umulsidi3 (USItype, USItype); #define add_ssaaaa(sh, sl, ah, al, bh, bl) \ do { \ if (__builtin_constant_p (bh) && (bh) == 0) \ - __asm__ ("{a%I4|add%I4c} %1,%3,%4\n\t{aze|addze} %0,%2" \ + __asm__ ("add%I4c %1,%3,%4\n\taddze %0,%2" \ : "=r" (sh), "=&r" (sl) : "r" (ah), "%r" (al), "rI" (bl));\ else if (__builtin_constant_p (bh) && (bh) == ~(UDItype) 0) \ - __asm__ ("{a%I4|add%I4c} %1,%3,%4\n\t{ame|addme} %0,%2" \ + __asm__ ("add%I4c %1,%3,%4\n\taddme %0,%2" \ : "=r" (sh), "=&r" (sl) : "r" (ah), "%r" (al), "rI" (bl));\ else \ - __asm__ ("{a%I5|add%I5c} %1,%4,%5\n\t{ae|adde} %0,%2,%3" \ + __asm__ ("add%I5c %1,%4,%5\n\tadde %0,%2,%3" \ : "=r" (sh), "=&r" (sl) \ : "%r" (ah), "r" (bh), "%r" (al), "rI" (bl)); \ } while (0) #define sub_ddmmss(sh, sl, ah, al, bh, bl) \ do { \ if (__builtin_constant_p (ah) && (ah) == 0) \ - __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{sfze|subfze} %0,%2" \ + __asm__ ("subf%I3c %1,%4,%3\n\tsubfze %0,%2" \ : "=r" (sh), "=&r" (sl) : "r" (bh), "rI" (al), "r" (bl));\ else if (__builtin_constant_p (ah) && (ah) == ~(UDItype) 0) \ - __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{sfme|subfme} %0,%2" \ + __asm__ ("subf%I3c %1,%4,%3\n\tsubfme %0,%2" \ : "=r" (sh), "=&r" (sl) : "r" (bh), "rI" (al), "r" (bl));\ else if (__builtin_constant_p (bh) && (bh) == 0) \ - __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{ame|addme} %0,%2" \ + __asm__ ("subf%I3c %1,%4,%3\n\taddme %0,%2" \ : "=r" (sh), "=&r" (sl) : "r" (ah), "rI" (al), "r" (bl));\ else if (__builtin_constant_p (bh) && (bh) == ~(UDItype) 0) \ - __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{aze|addze} %0,%2" \ + __asm__ ("subf%I3c %1,%4,%3\n\taddze %0,%2" \ : "=r" (sh), "=&r" (sl) : "r" (ah), "rI" (al), "r" (bl));\ else \ - __asm__ ("{sf%I4|subf%I4c} %1,%5,%4\n\t{sfe|subfe} %0,%3,%2" \ + __asm__ ("subf%I4c %1,%5,%4\n\tsubfe %0,%3,%2" \ : "=r" (sh), "=&r" (sl) \ : "r" (ah), "r" (bh), "rI" (al), "r" (bl)); \ } while (0) diff --git a/libgcc/static-object.mk b/libgcc/static-object.mk index 930f009cd42..4f536369f0d 100644 --- a/libgcc/static-object.mk +++ b/libgcc/static-object.mk @@ -24,7 +24,13 @@ $(error Unsupported file type: $o) endif endif -$(base)$(objext): $o - $(gcc_compile) -c -xassembler-with-cpp $< +$(base)$(objext): $o $(base).vis + $(gcc_compile) -c -xassembler-with-cpp -include $*.vis $< + +$(base).vis: $(base)_s$(objext) + $(gen-hide-list) + +$(base)_s$(objext): $o + $(gcc_s_compile) -c -xassembler-with-cpp $< endif diff --git a/libgcc/unwind-c.c b/libgcc/unwind-c.c index bd4941db3e2..eb50ad82a17 100644 --- a/libgcc/unwind-c.c +++ b/libgcc/unwind-c.c @@ -93,6 +93,8 @@ parse_lsda_header (struct _Unwind_Context *context, const unsigned char *p, #ifdef __USING_SJLJ_EXCEPTIONS__ #define PERSONALITY_FUNCTION __gcc_personality_sj0 #define __builtin_eh_return_data_regno(x) x +#elif defined(__SEH__) +#define PERSONALITY_FUNCTION __gcc_personality_imp #else #define PERSONALITY_FUNCTION __gcc_personality_v0 #endif @@ -107,6 +109,9 @@ PERSONALITY_FUNCTION (_Unwind_State state, struct _Unwind_Exception * ue_header, struct _Unwind_Context * context) #else +#ifdef __SEH__ +static +#endif _Unwind_Reason_Code PERSONALITY_FUNCTION (int, _Unwind_Action, _Unwind_Exception_Class, struct _Unwind_Exception *, struct _Unwind_Context *); @@ -227,3 +232,13 @@ PERSONALITY_FUNCTION (int version, _Unwind_SetIP (context, landing_pad); return _URC_INSTALL_CONTEXT; } + +#ifdef __SEH__ +EXCEPTION_DISPOSITION +__gcc_personality_seh0 (PEXCEPTION_RECORD ms_exc, void *this_frame, + PCONTEXT ms_orig_context, PDISPATCHER_CONTEXT ms_disp) +{ + return _GCC_specific_handler (ms_exc, this_frame, ms_orig_context, + ms_disp, __gcc_personality_imp); +} +#endif /* SEH */ diff --git a/libgcc/unwind-generic.h b/libgcc/unwind-generic.h index 4ff9017b88b..c9c993b2785 100644 --- a/libgcc/unwind-generic.h +++ b/libgcc/unwind-generic.h @@ -28,6 +28,11 @@ #ifndef _UNWIND_H #define _UNWIND_H +#ifdef __SEH__ +/* Only for _GCC_specific_handler. */ +#include <windows.h> +#endif + #ifndef HIDE_EXPORTS #pragma GCC visibility push(default) #endif @@ -86,8 +91,13 @@ struct _Unwind_Exception { _Unwind_Exception_Class exception_class; _Unwind_Exception_Cleanup_Fn exception_cleanup; + +#if !defined (__USING_SJLJ_EXCEPTIONS__) && defined (__SEH__) + _Unwind_Word private_[6]; +#else _Unwind_Word private_1; _Unwind_Word private_2; +#endif /* @@@ The IA-64 ABI says that this structure must be double-word aligned. Taking that literally does not make much sense generically. Instead we @@ -265,6 +275,13 @@ extern void * _Unwind_FindEnclosingFunction (void *pc); # error "What type shall we use for _sleb128_t?" #endif +#ifdef __SEH__ +/* Handles the mapping from SEH to GCC interfaces. */ +EXCEPTION_DISPOSITION _GCC_specific_handler (PEXCEPTION_RECORD, void *, + PCONTEXT, PDISPATCHER_CONTEXT, + _Unwind_Personality_Fn); +#endif + #ifdef __cplusplus } #endif diff --git a/libgcc/unwind-seh.c b/libgcc/unwind-seh.c new file mode 100644 index 00000000000..24e4280fde7 --- /dev/null +++ b/libgcc/unwind-seh.c @@ -0,0 +1,483 @@ +/* Structured Exception Handling (SEH) runtime interface routines. + Copyright (C) 2010 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/>. */ + +#include "tconfig.h" +#include "tsystem.h" +#include "coretypes.h" +#include "tm.h" +#include "unwind.h" + +#ifdef __SEH__ + +/* At the moment everything is written for x64, but in theory this could + also be used for i386, arm, mips and other extant embedded Windows. */ +#ifndef __x86_64__ +#error "Unsupported architecture." +#endif + +/* Define GCC's exception codes. See + http://msdn.microsoft.com/en-us/library/het71c37(v=VS.80).aspx + In particular, MS defines bits: + [31:30] = 3 (error), 2 (warning), 1 (info), 0 (success) + [29] = 1 (user-defined) + [28] = 0 (reserved) + We define bits: + [24:27] = type + [0:23] = magic + We set "magic" to "GCC", which is similar to MVC++ which uses "msc" + as the low 3 bytes of its user-defined codes for C++ exceptions. + + We define the ExceptionInformation entries as follows: + [0] = _Unwind_Exception pointer + [1] = target frame + [2] = target ip + [3] = target rdx +*/ + +#define STATUS_USER_DEFINED (1U << 29) + +#define GCC_MAGIC (('G' << 16) | ('C' << 8) | 'C') +#define GCC_EXCEPTION(TYPE) \ + (STATUS_USER_DEFINED | ((TYPE) << 24) | GCC_MAGIC) + +#define STATUS_GCC_THROW GCC_EXCEPTION (0) +#define STATUS_GCC_UNWIND GCC_EXCEPTION (1) +#define STATUS_GCC_FORCED GCC_EXCEPTION (2) + + +struct _Unwind_Context +{ + _Unwind_Word cfa; + _Unwind_Word ra; + _Unwind_Word reg[2]; + PDISPATCHER_CONTEXT disp; +}; + +/* Get the value of register INDEX as saved in CONTEXT. */ + +_Unwind_Word +_Unwind_GetGR (struct _Unwind_Context *c, int index) +{ + if (index < 0 || index > 2) + abort (); + return c->reg[index]; +} + +/* Overwrite the saved value for register INDEX in CONTEXT with VAL. */ + +void +_Unwind_SetGR (struct _Unwind_Context *c, int index, _Unwind_Word val) +{ + if (index < 0 || index > 2) + abort (); + c->reg[index] = val; +} + +/* Get the value of the CFA as saved in CONTEXT. */ + +_Unwind_Word +_Unwind_GetCFA (struct _Unwind_Context *c) +{ + return c->cfa; +} + +/* Retrieve the return address for CONTEXT. */ + +_Unwind_Ptr +_Unwind_GetIP (struct _Unwind_Context *c) +{ + return c->ra; +} + +/* Retrieve the return address and flag whether that IP is before + or after first not yet fully executed instruction. */ + +_Unwind_Ptr +_Unwind_GetIPInfo (struct _Unwind_Context *c, int *ip_before_insn) +{ + /* ??? Is there a concept of a signal context properly? There's + obviously an UNWP_PUSH_MACHFRAME opcode, but the runtime might + have arranged for that not to matter, really. */ + *ip_before_insn = 0; + return c->ra; +} + +/* Overwrite the return address for CONTEXT with VAL. */ + +void +_Unwind_SetIP (struct _Unwind_Context *c, _Unwind_Ptr val) +{ + c->ra = val; +} + +void * +_Unwind_GetLanguageSpecificData (struct _Unwind_Context *c) +{ + return c->disp->HandlerData; +} + +_Unwind_Ptr +_Unwind_GetRegionStart (struct _Unwind_Context *c) +{ + return c->disp->FunctionEntry->BeginAddress + c->disp->ImageBase; +} + +void * +_Unwind_FindEnclosingFunction (void *pc) +{ + PRUNTIME_FUNCTION entry; + ULONG64 ImageBase; + + entry = RtlLookupFunctionEntry ((ULONG64)pc, &ImageBase, NULL); + + return (entry ? (void *)(entry->BeginAddress + ImageBase) : NULL); +} + +_Unwind_Ptr +_Unwind_GetDataRelBase (struct _Unwind_Context *c ATTRIBUTE_UNUSED) +{ + return 0; +} + +_Unwind_Ptr +_Unwind_GetTextRelBase (struct _Unwind_Context *c) +{ + return c->disp->ImageBase; +} + + +/* The two-phase unwind process that GCC uses is ordered differently + from the two-phase unwind process that SEH uses. The mechansism + that GCC uses is to have the filter return _URC_HANDER_FOUND; the + mechanism that SEH uses is for the filter function call back into + the unwinder. + + An Ideal port to SEH would have GCC emit handler functions that + can be called, given a pointer to the "EstablisherFrame" (i.e. + the frame pointer base of the user-level function) can manipulate + the user-level variables within the user-level function's stack + frame. Once done manipulating the variables, it would return + a ExceptionContinueSearch, and the unwind process would continue. + + GCC has always done things a bit differently. We continue to + transfer control back into the user-level function which, once + done manipulating the user-level variables, re-throws the exception. */ + +/* The "real" language-specific personality handler forwards to here + where we handle the MS SEH state and transforms it into the GCC + unwind state as per GCC's <unwind.h>, at which point we defer to + the regular language-specfic exception handler, which is passed in. */ + +EXCEPTION_DISPOSITION +_GCC_specific_handler (PEXCEPTION_RECORD ms_exc, void *this_frame, + PCONTEXT ms_orig_context, PDISPATCHER_CONTEXT ms_disp, + _Unwind_Personality_Fn gcc_per) +{ + DWORD ms_flags = ms_exc->ExceptionFlags; + DWORD ms_code = ms_exc->ExceptionCode; + + struct _Unwind_Exception *gcc_exc + = (struct _Unwind_Exception *) ms_exc->ExceptionInformation[0]; + struct _Unwind_Context gcc_context; + _Unwind_Action gcc_action; + _Unwind_Reason_Code gcc_reason; + + if (ms_flags & EXCEPTION_TARGET_UNWIND) + { + /* This frame is known to be the target frame. We've already + "installed" the target_ip and RAX value via the arguments + to RtlUnwindEx. All that's left is to set the RDX value + and "continue" to have the context installed. */ + ms_disp->ContextRecord->Rdx = ms_exc->ExceptionInformation[3]; + return ExceptionContinueSearch; + } + + if (ms_code == STATUS_GCC_UNWIND) + { + /* This is a colliding exception that we threw so that we could + cancel the already in-flight exception and stop in a frame + that wanted to perform some unwind action. The only relevant + test is that we're the target frame. */ + if (ms_exc->ExceptionInformation[1] == (_Unwind_Ptr) this_frame) + { + RtlUnwindEx (this_frame, ms_exc->ExceptionInformation[2], + ms_exc, gcc_exc, ms_orig_context, + ms_disp->HistoryTable); + abort (); + } + return ExceptionContinueSearch; + } + + gcc_context.cfa = ms_disp->ContextRecord->Rsp; + gcc_context.ra = ms_disp->ControlPc; + gcc_context.reg[0] = 0xdeadbeef; /* These are write-only. */ + gcc_context.reg[1] = 0xdeadbeef; + gcc_context.disp = ms_disp; + + if (ms_code == STATUS_GCC_FORCED) + { + _Unwind_Stop_Fn stop = (_Unwind_Stop_Fn) gcc_exc->private_[0]; + void *stop_argument = (void *) gcc_exc->private_[4]; + + gcc_action = _UA_FORCE_UNWIND | _UA_CLEANUP_PHASE; + + stop (1, gcc_action, gcc_exc->exception_class, gcc_exc, + &gcc_context, stop_argument); + + goto phase2; + } + + /* ??? TODO: handling non-gcc user-defined exceptions as foreign. */ + if (ms_code != STATUS_GCC_THROW) + return ExceptionContinueSearch; + + if (ms_flags & (EXCEPTION_UNWINDING | EXCEPTION_EXIT_UNWIND)) + { + /* This is Phase 2. */ + /* We know this isn't the target frame because we've already tested + EXCEPTION_TARGET_UNWIND. The remaining possibility is that the + gcc personality has unwind code to run. */ + + gcc_action = _UA_CLEANUP_PHASE; + phase2: + gcc_reason = gcc_per (1, gcc_action, gcc_exc->exception_class, + gcc_exc, &gcc_context); + + if (gcc_reason == _URC_CONTINUE_UNWIND) + return ExceptionContinueSearch; + + if (gcc_reason == _URC_INSTALL_CONTEXT) + { + /* Scratch space for the bits for the unwind catch. */ + ms_exc->ExceptionInformation[1] = (_Unwind_Ptr) this_frame; + ms_exc->ExceptionInformation[2] = gcc_context.ra; + ms_exc->ExceptionInformation[3] = gcc_context.reg[1]; + + /* Cancel the current exception by raising another. */ + RaiseException (STATUS_GCC_UNWIND, EXCEPTION_NONCONTINUABLE, + 4, ms_exc->ExceptionInformation); + + /* Is RaiseException declared noreturn? */ + } + + /* In _Unwind_RaiseException_Phase2 we return _URC_FATAL_PHASE2_ERROR. */ + } + else + { + /* This is Phase 1. */ + gcc_reason = gcc_per (1, _UA_SEARCH_PHASE, gcc_exc->exception_class, + gcc_exc, &gcc_context); + + if (gcc_reason == _URC_CONTINUE_UNWIND) + return ExceptionContinueSearch; + + if (gcc_reason == _URC_HANDLER_FOUND) + { + /* We really need some of the information that GCC's personality + routines compute during phase 2 right now, like the target IP. + Go ahead and ask for it now, and cache it. */ + gcc_reason = gcc_per (1, _UA_CLEANUP_PHASE | _UA_HANDLER_FRAME, + gcc_exc->exception_class, gcc_exc, + &gcc_context); + if (gcc_reason != _URC_INSTALL_CONTEXT) + abort (); + + gcc_exc->private_[1] = (_Unwind_Ptr) this_frame; + gcc_exc->private_[2] = gcc_context.ra; + gcc_exc->private_[3] = gcc_context.reg[1]; + + ms_exc->NumberParameters = 4; + ms_exc->ExceptionInformation[1] = (_Unwind_Ptr) this_frame; + ms_exc->ExceptionInformation[2] = gcc_context.ra; + ms_exc->ExceptionInformation[3] = gcc_context.reg[1]; + + /* Begin phase 2. Perform the unwinding. */ + RtlUnwindEx (this_frame, gcc_context.ra, ms_exc, gcc_exc, + ms_orig_context, ms_disp->HistoryTable); + } + + /* In _Unwind_RaiseException we return _URC_FATAL_PHASE1_ERROR. */ + } + abort (); +} + +/* Raise an exception, passing along the given exception object. */ + +_Unwind_Reason_Code +_Unwind_RaiseException (struct _Unwind_Exception *exc) +{ + memset (exc->private_, 0, sizeof (exc->private_)); + + /* The ExceptionInformation array will have only 1 element, EXC. */ + RaiseException (STATUS_GCC_THROW, 0, 1, (ULONG_PTR *)&exc); + + /* The exception handler installed in crt0 will continue any GCC + exception that reaches there (and isn't marked non-continuable). + Returning allows the C++ runtime to call std::terminate. */ + return _URC_END_OF_STACK; +} + +/* Resume propagation of an existing exception. This is used after + e.g. executing cleanup code, and not to implement rethrowing. */ + +void +_Unwind_Resume (struct _Unwind_Exception *gcc_exc) +{ + UNWIND_HISTORY_TABLE ms_history; + EXCEPTION_RECORD ms_exc; + CONTEXT ms_context; + + memset (&ms_exc, 0, sizeof(ms_exc)); + memset (&ms_history, 0, sizeof(ms_history)); + + /* ??? Not 100% perfect, since we aren't passing on the *original* + exception context, but should be good enough. */ + ms_exc.ExceptionCode = STATUS_GCC_THROW; + ms_exc.ExceptionFlags = EXCEPTION_NONCONTINUABLE; + ms_exc.NumberParameters = 4; + ms_exc.ExceptionInformation[0] = (ULONG_PTR) gcc_exc; + ms_exc.ExceptionInformation[1] = gcc_exc->private_[1]; + ms_exc.ExceptionInformation[2] = gcc_exc->private_[2]; + ms_exc.ExceptionInformation[3] = gcc_exc->private_[3]; + + ms_context.ContextFlags = CONTEXT_ALL; + RtlCaptureContext (&ms_context); + + RtlUnwindEx ((void *) gcc_exc->private_[1], gcc_exc->private_[2], + &ms_exc, gcc_exc, &ms_context, &ms_history); + + /* Is RtlUnwindEx declared noreturn? */ + abort (); +} + +static _Unwind_Reason_Code +_Unwind_ForcedUnwind_Phase2 (struct _Unwind_Exception *exc) +{ + _Unwind_Stop_Fn stop; + void * stop_argument; + + RaiseException (STATUS_GCC_FORCED, 0, 1, (ULONG_PTR *)&exc); + + /* If we get here, we got to top-of-stack. */ + /* ??? We no longer have a context pointer to pass in. */ + + stop = (_Unwind_Stop_Fn) exc->private_[0]; + stop_argument = (void *) exc->private_[4]; + stop (1, _UA_FORCE_UNWIND | _UA_CLEANUP_PHASE | _UA_END_OF_STACK, + exc->exception_class, exc, NULL, stop_argument); + + return _UA_END_OF_STACK; +} + +_Unwind_Reason_Code +_Unwind_Resume_or_Rethrow (struct _Unwind_Exception *exc) +{ + if (exc->private_[0] == 0) + _Unwind_RaiseException (exc); + else + _Unwind_ForcedUnwind_Phase2 (exc); + abort (); +} + +/* Raise an exception for forced unwinding. */ + +_Unwind_Reason_Code +_Unwind_ForcedUnwind (struct _Unwind_Exception *exc, + _Unwind_Stop_Fn stop, void * stop_argument) +{ + /* ??? This is a hack that only works with _GCC_specific_handler. + There's no way to invoke STOP within frames that use a different + exception handler. This is essentially just good enough to run + the code within the gcc testsuite. */ + + memset (exc->private_, 0, sizeof (exc->private_)); + exc->private_[0] = (_Unwind_Ptr) stop; + exc->private_[4] = (_Unwind_Ptr) stop_argument; + + return _Unwind_ForcedUnwind_Phase2 (exc); +} + +/* A convenience function that calls the exception_cleanup field. */ + +void +_Unwind_DeleteException (struct _Unwind_Exception *exc) +{ + if (exc->exception_cleanup) + (*exc->exception_cleanup) (_URC_FOREIGN_EXCEPTION_CAUGHT, exc); +} + +/* Perform stack backtrace through unwind data. */ + +_Unwind_Reason_Code +_Unwind_Backtrace(_Unwind_Trace_Fn trace ATTRIBUTE_UNUSED, + void *trace_argument ATTRIBUTE_UNUSED) +{ +#if 0 + UNWIND_HISTORY_TABLE ms_history; + CONTEXT ms_context; + struct _Unwind_Context gcc_context; + + memset (&ms_history, 0, sizeof(ms_history)); + memset (&gcc_context, 0, sizeof(gcc_context)); + + ms_context.ContextFlags = CONTEXT_ALL; + RtlCaptureContext (&ms_context); + + gcc_context.disp.ContextRecord = &ms_context; + gcc_context.disp.HistoryTable = &ms_history; + + while (1) + { + gcc_context.disp.ControlPc = ms_context.Rip; + gcc_context.disp.FunctionEntry + = RtlLookupFunctionEntry (ms_context.Rip, &gcc_context.disp.ImageBase, + &ms_history); + + if (gcc_context.disp.FunctionEntry) + { + gcc_context.disp.LanguageHandler + = RtlVirtualUnwind (0, gcc_context.disp.ImageBase, ms_context.Rip, + gcc_context.disp.FunctionEntry, &ms_context, + &gcc_context.disp.HandlerData, + &gcc_context.disp.EstablisherFrame, NULL); + } + else + { + ms_context.Rip = *(ULONG_PTR *)ms_context.Rsp; + ms_context.Rsp += 8; + } + + /* Call trace function. */ + if (trace (&gcc_context, trace_argument) != _URC_NO_REASON) + return _URC_FATAL_PHASE1_ERROR; + + /* ??? Check for invalid stack pointer. */ + if (ms_context.Rip == 0) + return _URC_END_OF_STACK; + } +#else + return _URC_END_OF_STACK; +#endif +} +#endif /* __SEH__ */ |