diff options
author | Nick Clifton <nickc@redhat.com> | 2015-12-04 17:24:30 +0000 |
---|---|---|
committer | Nick Clifton <nickc@gcc.gnu.org> | 2015-12-04 17:24:30 +0000 |
commit | 04a9ae287f6d76c60464c57be98550a25b358c34 (patch) | |
tree | 567b5a149156fde352ef52d1373ff08ead34394d /libgcc | |
parent | 4b5d538ba7ff4c9d69fd73e1bb2ce88e3fca7562 (diff) | |
download | gcc-04a9ae287f6d76c60464c57be98550a25b358c34.zip gcc-04a9ae287f6d76c60464c57be98550a25b358c34.tar.gz gcc-04a9ae287f6d76c60464c57be98550a25b358c34.tar.bz2 |
gcc * config.gcc (extra_gcc_objs): Define for MSP430.
* common/config/msp430/msp430-common.c (msp430_handle_option):
Pass both -mmcu and -mcpu on to the back end if they are both
defined.
* config/msp430/msp430.c (hwmult_name): New function.
(msp430_option_override): If an unrecognised MCU name is
detected only warn if the user has not provided suitable
-mhwmult and -mcpu options. Use msp430_warn_mcu to control
warning messages. Generate warnings about conflicts between
-mmcu and -mcpu and -mhwmult options.
If neither -mcpu nor -mmcu have been specified but -mhwmult=
f5series has the select the 430X isa.
(msp430_no_hwmult): If -mmcu has not been specified and
msp430_hwmult_type is AUTO then return true.
* config/msp430/msp430.h (EXTRA_SPEC_FUNCTIONS): Define.
(LIB_SPEC): Add hardware multiply library selection.
* config/msp430/t-msp430: Delete hardware multiply multilibs.
Add rule to build driver-msp430.o
* config/msp430/driver-msp430.c: New file.
* config/msp430/msp430.opt (warn-mcu): New option.
* doc/invoke.texi: Update description of -mhwmult=auto.
Document -mwarn-mcu option.
tests * gcc.target/msp430/msp_abi_div_funcs.c: New test.
* gcc.target/msp430/mul_main.h: New test support file.
* gcc.target/msp430/mul_none.c: New test.
* gcc.target/msp430/mul_16bit.c: New test.
* gcc.target/msp430/mul_32bit.c: New test.
* gcc.target/msp430/mul_f5.c: New test.
libgcc * config/msp430/mpy.c (__mulhi3): Use a faster algorithm.
Allow for the second argument being negative.
* config.host (extra_parts): Define for MSP430. Create separate
libraries for each of the hardware multiply formats.
* config/msp430/lib2hw_mul.S: Build only the multiply routines
that are needed.
* config/msp430/lib2mul.c: Likewise.
* config/msp430/t-msp430 (LIB2ADD): Remove lib2hw_mul.S.
Add rules to build hardware multiply libraries.
* config/msp430/lib2divSI.c: (__mspabi_divlu): Alias for
__mspabi_divul function.
(__mspabi_divllu): New stub function.
From-SVN: r231286
Diffstat (limited to 'libgcc')
-rw-r--r-- | libgcc/ChangeLog | 15 | ||||
-rw-r--r-- | libgcc/config.host | 1 | ||||
-rw-r--r-- | libgcc/config/msp430/lib2divSI.c | 29 | ||||
-rw-r--r-- | libgcc/config/msp430/lib2hw_mul.S | 215 | ||||
-rw-r--r-- | libgcc/config/msp430/lib2mul.c | 37 | ||||
-rw-r--r-- | libgcc/config/msp430/mpy.c | 21 | ||||
-rw-r--r-- | libgcc/config/msp430/t-msp430 | 28 |
7 files changed, 293 insertions, 53 deletions
diff --git a/libgcc/ChangeLog b/libgcc/ChangeLog index 8143db2..003971b 100644 --- a/libgcc/ChangeLog +++ b/libgcc/ChangeLog @@ -1,3 +1,18 @@ +2015-12-04 Nick Clifton <nickc@redhat.com> + + * config/msp430/mpy.c (__mulhi3): Use a faster algorithm. + Allow for the second argument being negative. + * config.host (extra_parts): Define for MSP430. Create separate + libraries for each of the hardware multiply formats. + * config/msp430/lib2hw_mul.S: Build only the multiply routines + that are needed. + * config/msp430/lib2mul.c: Likewise. + * config/msp430/t-msp430 (LIB2ADD): Remove lib2hw_mul.S. + Add rules to build hardware multiply libraries. + * config/msp430/lib2divSI.c: (__mspabi_divlu): Alias for + __mspabi_divul function. + (__mspabi_divllu): New stub function. + 2015-12-01 John David Anglin <danglin@gcc.gnu.org> * config/pa/fptr.c (__canonicalize_funcptr_for_compare): Initialize diff --git a/libgcc/config.host b/libgcc/config.host index 9a58beb..b16f52a 100644 --- a/libgcc/config.host +++ b/libgcc/config.host @@ -942,6 +942,7 @@ moxie-*-rtems*) ;; msp430*-*-elf) tmake_file="$tm_file t-crtstuff t-fdpbit msp430/t-msp430" + extra_parts="$extra_parts libmul_none.a libmul_16.a libmul_32.a libmul_f5.a" ;; nds32*-elf*) # Basic makefile fragment and extra_parts for crt stuff. diff --git a/libgcc/config/msp430/lib2divSI.c b/libgcc/config/msp430/lib2divSI.c index cc45c4c..fa6ac45 100644 --- a/libgcc/config/msp430/lib2divSI.c +++ b/libgcc/config/msp430/lib2divSI.c @@ -40,3 +40,32 @@ typedef int word_type __attribute__ ((mode (__word__))); #define NAME_MODE si #include "msp430-divmod.h" + +/* ---------------------------------------------------------------------*/ + +/* There is a typo in the MSP430 ABI document. It calls the unsigned + long integer division function __mspabi_divlu when it should be + __mspabi_divul. Likewise the unsigned long long integer division + function is called __mspabi_divllu when it should be __mspabi_divull. + + Earlier versions of this toolchain used generate the ABI compliant + names, so in order to support object files built with those tools + we provide stub functions that call the correct routines. */ + +asm (".global __mspabi_divlu\n\ + .set __mspabi_divlu, __mspabi_divul"); + +/* We cannot use the same trick for __mspabi_divllu as that is defined + in a different file. Instead we create a stub here. The cost of + executing the branch instruction will be trivial compared to the + cost of executing a long long division. */ + +#ifdef __MSP430X_LARGE__ +asm (".global __mspabi_divllu\n\ + __mspabi_divllu:\n\ + BRA #__mspabi_divull"); +#else +asm (".global __mspabi_divllu\n\ + __mspabi_divllu:\n\ + BR #__mspabi_divull"); +#endif diff --git a/libgcc/config/msp430/lib2hw_mul.S b/libgcc/config/msp430/lib2hw_mul.S index b686d8e..908451d 100644 --- a/libgcc/config/msp430/lib2hw_mul.S +++ b/libgcc/config/msp430/lib2hw_mul.S @@ -20,17 +20,42 @@ ; see the files COPYING3 and COPYING.RUNTIME respectively. If not, see ; <http://www.gnu.org/licenses/>. -.macro start_func name - .pushsection .text.\name,"ax",@progbits + ;; Macro to start a multiply function. Each function has three + ;; names, and hence three entry points - although they all go + ;; through the same code. The first name is the version generated + ;; by GCC. The second is the MSP430 EABI mandated name for the + ;; *software* version of the function. The third is the EABI + ;; mandated name for the *hardware* version of the function. + ;; + ;; Since we are using the hardware and software names to point + ;; to the same code this effectively means that we are mapping + ;; the software function onto the hardware function. Thus if + ;; the library containing this code is linked into an application + ;; (before the libgcc.a library) *all* multiply functions will + ;; be mapped onto the hardware versions. + ;; + ;; We construct each function in its own section so that linker + ;; garbage collection can be used to delete any unused functions + ;; from this file. +.macro start_func gcc_name eabi_soft_name eabi_hard_name + .pushsection .text.\gcc_name,"ax",@progbits .p2align 1 - .global \name - .type \name , @function -\name: + .global \eabi_hard_name + .type \eabi_hard_name , @function +\eabi_hard_name: + .global \eabi_soft_name + .type \eabi_soft_name , @function +\eabi_soft_name: + .global \gcc_name + .type \gcc_name , @function +\gcc_name: PUSH.W sr ; Save current interrupt state DINT ; Disable interrupts NOP ; Account for latency .endm + + ;; End a function started with the start_func macro. .macro end_func name #ifdef __MSP430X_LARGE__ POP.W sr @@ -42,6 +67,29 @@ .popsection .endm + + ;; Like the start_func macro except that it is used to + ;; create a false entry point that just jumps to the + ;; software function (implemented elsewhere). +.macro fake_func gcc_name eabi_soft_name eabi_hard_name + .pushsection .text.\gcc_name,"ax",@progbits + .p2align 1 + .global \eabi_hard_name + .type \eabi_hard_name , @function +\eabi_hard_name: + .global \gcc_name + .type \gcc_name , @function +\gcc_name: +#ifdef __MSP430X_LARGE__ + BRA \eabi_soft_name +#else + BR \eabi_soft_name +#endif + .size \gcc_name , . - \gcc_name + .popsection +.endm + + .macro mult16 OP1, OP2, RESULT ;* * 16-bit hardware multiply: int16 = int16 * int16 ;* @@ -160,7 +208,66 @@ .endm -;; First generation MSP430 hardware multiplies .... +;; EABI mandated names: +;; +;; int16 __mspabi_mpyi (int16 x, int16 y) +;; Multiply int by int. +;; int16 __mspabi_mpyi_hw (int16 x, int16 y) +;; Multiply int by int. Uses hardware MPY16 or MPY32. +;; int16 __mspabi_mpyi_f5hw (int16 x, int16 y) +;; Multiply int by int. Uses hardware MPY32 (F5xx devices and up). +;; +;; int32 __mspabi_mpyl (int32 x, int32 y); +;; Multiply long by long. +;; int32 __mspabi_mpyl_hw (int32 x, int32 y) +;; Multiply long by long. Uses hardware MPY16. +;; int32 __mspabi_mpyl_hw32 (int32 x, int32 y) +;; Multiply long by long. Uses hardware MPY32 (F4xx devices). +;; int32 __mspabi_mpyl_f5hw (int32 x, int32 y) +;; Multiply long by long. Uses hardware MPY32 (F5xx devices and up). +;; +;; int64 __mspabi_mpyll (int64 x, int64 y) +;; Multiply long long by long long. +;; int64 __mspabi_mpyll_hw (int64 x, int64 y) +;; Multiply long long by long long. Uses hardware MPY16. +;; int64 __mspabi_mpyll_hw32 (int64 x, int64 y) +;; Multiply long long by long long. Uses hardware MPY32 (F4xx devices). +;; int64 __mspabi_mpyll_f5hw (int64 x, int64 y) +;; Multiply long long by long long. Uses hardware MPY32 (F5xx devices and up). +;; +;; int32 __mspabi_mpysl (int16 x, int16 y) +;; Multiply int by int; result is long. +;; int32 __mspabi_mpysl_hw(int16 x, int16 y) +;; Multiply int by int; result is long. Uses hardware MPY16 or MPY32 +;; int32 __mspabi_mpysl_f5hw(int16 x, int16 y) +;; Multiply int by int; result is long. Uses hardware MPY32 (F5xx devices and up). +;; +;; int64 __mspabi_mpysll(int32 x, int32 y) +;; Multiply long by long; result is long long. +;; int64 __mspabi_mpysll_hw(int32 x, int32 y) +;; Multiply long by long; result is long long. Uses hardware MPY16. +;; int64 __mspabi_mpysll_hw32(int32 x, int32 y) +;; Multiply long by long; result is long long. Uses hardware MPY32 (F4xx devices). +;; int64 __mspabi_mpysll_f5hw(int32 x, int32 y) +;; Multiply long by long; result is long long. Uses hardware MPY32 (F5xx devices and up). +;; +;; uint32 __mspabi_mpyul(uint16 x, uint16 y) +;; Multiply unsigned int by unsigned int; result is unsigned long. +;; uint32 __mspabi_mpyul_hw(uint16 x, uint16 y) +;; Multiply unsigned int by unsigned int; result is unsigned long. Uses hardware MPY16 or MPY32 +;; uint32 __mspabi_mpyul_f5hw(uint16 x, uint16 y) +;; Multiply unsigned int by unsigned int; result is unsigned long. Uses hardware MPY32 (F5xx devices and up). +;; +;; uint64 __mspabi_mpyull(uint32 x, uint32 y) +;; Multiply unsigned long by unsigned long; result is unsigned long long. +;; uint64 __mspabi_mpyull_hw(uint32 x, uint32 y) +;; Multiply unsigned long by unsigned long; result is unsigned long long. Uses hardware MPY16 +;; uint64 __mspabi_mpyull_hw32(uint32 x, uint32 y) +;; Multiply unsigned long by unsigned long; result is unsigned long long. Uses hardware MPY32 (F4xx devices). +;; uint64 _ _mspabi_mpyull_f5hw(uint32 x, uint32 y) +;; Multiply unsigned long by unsigned long; result is unsigned long long. Uses hardware MPY32 (F5xx devices and up) + + .set MPY_OP1, 0x0130 .set MPY_OP1_S, 0x0132 @@ -169,58 +276,94 @@ .set MAC_OP2, 0x0138 .set RESULT_LO, 0x013A .set RESULT_HI, 0x013C - - start_func __mulhi2 + +#if defined MUL_16 +;; First generation MSP430 hardware multiplies ... + + start_func __mulhi2 __mspabi_mpyi __mspabi_mpyi_hw mult16 MPY_OP1, MPY_OP2, RESULT_LO - end_func __mulhi2 + end_func __mulhi2 - start_func __mulsihi2 + start_func __mulsihi2 __mspabi_mpysl __mspabi_mpysl_hw mult1632 MPY_OP1_S, MPY_OP2, RESULT_LO, RESULT_HI - end_func __mulsihi2 + end_func __mulsihi2 - start_func __umulsihi2 + start_func __umulsihi2 __mspabi_mpyul _mspabi_mpyul_hw mult1632 MPY_OP1, MPY_OP2, RESULT_LO, RESULT_HI - end_func __umulsihi2 + end_func __umulsihi2 - start_func __mulsi2 + start_func __mulsi2 __mspabi_mpyl __mspabi_mpyl_hw mult32 MPY_OP1, MPY_OP2, MAC_OP1, MAC_OP2, RESULT_LO, RESULT_HI - end_func __mulsi2 + end_func __mulsi2 - start_func __mulsi2_hw32 + ;; FIXME: We do not have hardware implementations of these + ;; routines, so just jump to the software versions instead. + fake_func __muldisi2 __mspabi_mpysll __mspabi_mpysll_hw + fake_func __umuldisi2 __mspabi_mpyull __mspabi_mpyull_hw + fake_func __muldi3 __mspabi_mpyll __mspabi_mpyll_hw + +#elif defined MUL_32 +;; Second generation MSP430 hardware multiplies ... + + start_func __mulhi2 __mspabi_mpyi __mspabi_mpyi_hw + mult16 MPY_OP1, MPY_OP2, RESULT_LO + end_func __mulhi2 + + start_func __mulsihi2 __mspabi_mpysl __mspabi_mpysl_hw + mult1632 MPY_OP1_S, MPY_OP2, RESULT_LO, RESULT_HI + end_func __mulsihi2 + + start_func __umulsihi2 __mspabi_mpyul _mspabi_mpyul_hw + mult1632 MPY_OP1, MPY_OP2, RESULT_LO, RESULT_HI + end_func __umulsihi2 + + start_func __mulsi2_hw32 __mspabi_mpyl __mspabi_mpyl_hw32 mult32_hw 0x0140, 0x0142, 0x0150, 0x0152, 0x0154, 0x0156 - end_func __mulsi2_hw32 + end_func __mulsi2_hw32 - start_func __muldisi2_hw32 + start_func __muldisi2 __mspabi_mpysll __mspabi_mpysll_hw32 mult3264_hw 0x0144, 0x146, 0x0150, 0x0152, 0x0154, 0x0156, 0x0158, 0x015A - end_func __muldisi2_hw32 + end_func __muldisi2 - start_func __umuldisi2_hw32 + start_func __umuldisi2 __mspabi_mpyull __mspabi_mpyull_hw32 mult3264_hw 0x0140, 0x142, 0x0150, 0x0152, 0x0154, 0x0156, 0x0158, 0x015A - end_func __umuldisi2_hw32 - -/* The F5xxx series of MCUs support the same 16-bit hardware - multiply, but it is accessed from different memory registers. */ + end_func __umuldisi2 + + ;; FIXME: Add a hardware version of this function. + fake_func __muldi3 __mspabi_mpyll __mspabi_mpyll_hw32 - start_func __mulhi2_f5 +#elif defined MUL_F5 +/* The F5xxx series of MCUs support the same 16-bit and 32-bit multiply + as the second generation hardware, but they are accessed from different + memory registers. */ + + start_func __mulhi2_f5 __mspabi_mpyi __mspabi_mpyi_f5hw mult16 0x04C0, 0x04C8, 0x04CA - end_func __mulhi2_f5 + end_func __mulhi2_f5 - start_func __mulsihi2_f5 + start_func __mulsihi2 __mspabi_mpysl __mspabi_mpysl_f5hw mult1632 0x04C2, 0x04C8, 0x04CA, 0x04CC - end_func __mulsihi2_f5 + end_func __mulsihi2 - start_func __umulsihi2_f5 + start_func __umulsihi2 __mspabi_mpyul _mspabi_mpyul_f5hw mult1632 0x04C0, 0x04C8, 0x04CA, 0x04CC - end_func __umulsihi2_f5 + end_func __umulsihi2 - start_func __mulsi2_f5 + start_func __mulsi2_f5 __mspabi_mpyl __mspabi_mpyl_f5hw mult32_hw 0x04D0, 0x04D2, 0x04E0, 0x04E2, 0x04E4, 0x04E6 - end_func __mulsi2_f5 + end_func __mulsi2_f5 - start_func __muldisi2_f5 + start_func __muldisi2 __mspabi_mpysll __mspabi_mpysll_f5hw mult3264_hw 0x04D4, 0x04D6, 0x04E0, 0x04E2, 0x04E4, 0x04E6, 0x04E8, 0x04EA - end_func __muldisi2_f5 + end_func __muldisi2 - start_func __umuldisi2_f5 + start_func __umuldisi2 __mspabi_mpyull __mspabi_mpyull_f5hw mult3264_hw 0x04D0, 0x04D2, 0x04E0, 0x04E2, 0x04E4, 0x04E6, 0x04E8, 0x04EA - end_func __umuldisi2_f5 + end_func __umuldisi2 + + ;; FIXME: Add a hardware version of this function. + fake_func __muldi3 __mspabi_mpyll __mspabi_mpyll_f5hw + +#else +#error MUL type not defined +#endif diff --git a/libgcc/config/msp430/lib2mul.c b/libgcc/config/msp430/lib2mul.c index ecd3b85..3aa0f92 100644 --- a/libgcc/config/msp430/lib2mul.c +++ b/libgcc/config/msp430/lib2mul.c @@ -30,29 +30,44 @@ typedef unsigned int uint08_type __attribute__ ((mode (QI))); #define C3B(a,b,c) a##b##c #define C3(a,b,c) C3B(a,b,c) +#if defined MUL_NONE -#define UINT_TYPE uint16_type -#define BITS_MINUS_1 15 -#define NAME_MODE hi - -#include "msp430-mul.h" +/* The software multiply library needs __mspabi_mpyll. */ #undef UINT_TYPE #undef BITS_MINUS_1 #undef NAME_MODE -#define UINT_TYPE uint08_type -#define BITS_MINUS_1 7 -#define NAME_MODE qi +#define UINT_TYPE uint32_type +#define BITS_MINUS_1 31 +#define NAME_MODE si #include "msp430-mul.h" +#elif defined MUL_16 + +signed long long +__mspabi_mpysll (signed long a, signed long b) +{ + return (signed long long) a * (signed long long) b; +} + +unsigned long long +__mspabi_mpyull (unsigned long a, unsigned long b) +{ + return (unsigned long long) a * (unsigned long long) b; +} + +#else + #undef UINT_TYPE #undef BITS_MINUS_1 #undef NAME_MODE -#define UINT_TYPE uint32_type -#define BITS_MINUS_1 31 -#define NAME_MODE si +#define UINT_TYPE uint08_type +#define BITS_MINUS_1 7 +#define NAME_MODE qi #include "msp430-mul.h" + +#endif /* MUL_NONE */ diff --git a/libgcc/config/msp430/mpy.c b/libgcc/config/msp430/mpy.c index 57cffd0..3842d86 100644 --- a/libgcc/config/msp430/mpy.c +++ b/libgcc/config/msp430/mpy.c @@ -4,12 +4,23 @@ extern int __mulhi3 (int, int); int __mulhi3 (int x, int y) { - volatile int rv = 0; + char bit; + int neg = 0; + int rv = 0; - while (y > 0) + if (y < 0) { - rv += x; - y --; + y = - y; + neg = 1; } - return rv; + + for (bit = 0; y && bit < sizeof (y) * 8; bit ++) + { + if (y & 1) + rv += x; + x <<= 1; + y >>= 1; + } + + return neg ? - rv : rv; } diff --git a/libgcc/config/msp430/t-msp430 b/libgcc/config/msp430/t-msp430 index 5c0cccd..3ac9955 100644 --- a/libgcc/config/msp430/t-msp430 +++ b/libgcc/config/msp430/t-msp430 @@ -35,7 +35,6 @@ LIB2ADD = \ $(srcdir)/config/msp430/srai.S \ $(srcdir)/config/msp430/srli.S \ $(srcdir)/config/msp430/cmpsi2.S \ - $(srcdir)/config/msp430/lib2hw_mul.S \ $(srcdir)/config/msp430/floatunhisf.c \ $(srcdir)/config/msp430/floatunhidf.c \ $(srcdir)/config/msp430/floathidf.c \ @@ -44,6 +43,33 @@ LIB2ADD = \ HOST_LIBGCC2_CFLAGS += -Os -ffunction-sections -fdata-sections -mhwmult=none +lib2_mul_none.o: $(srcdir)/config/msp430/lib2mul.c + $(gcc_compile) $^ -c -DMUL_NONE + +lib2_mul_16bit.o: $(srcdir)/config/msp430/lib2mul.c + $(gcc_compile) $^ -c -DMUL_16 + +lib2hw_mul_16.o: $(srcdir)/config/msp430/lib2hw_mul.S + $(gcc_compile) $^ -c -DMUL_16 + +lib2hw_mul_32.o: $(srcdir)/config/msp430/lib2hw_mul.S + $(gcc_compile) $^ -c -DMUL_32 + +lib2hw_mul_f5.o: $(srcdir)/config/msp430/lib2hw_mul.S + $(gcc_compile) $^ -c -DMUL_F5 + +libmul_none.a: lib2_mul_none.o + $(AR_CREATE_FOR_TARGET) $@ $^ + +libmul_16.a: lib2hw_mul_16.o lib2_mul_16bit.o + $(AR_CREATE_FOR_TARGET) $@ $^ + +libmul_32.a: lib2hw_mul_32.o + $(AR_CREATE_FOR_TARGET) $@ $^ + +libmul_f5.a: lib2hw_mul_f5.o + $(AR_CREATE_FOR_TARGET) $@ $^ + # Local Variables: # mode: Makefile # End: |